Implementere toveis SMS i .Net


onsdag 16. juni 2010 PSWinCom SMS C#

At en tjeneste benytter toveis SMS vil si at den både kan motta meldinger fra brukere (mobile originated, MO), og at den kan sende meldinger til brukere (mobile terminated, MT). Å lage en slik tjenste som bruker PSWinCom's SMS gateway er veldig enkelt, takket være gode integrasjonsgrensesnitt. I denne artikkelen vil jeg implementere en slik tjeneste i .NET / C#.

Jeg registrerer meg hele tiden på ulike nettsteder, som alle ber meg om å spesifisere et passord. Og da er det veldig dumt å bruke det samme passordet hele tiden. Jeg ønsker derfor å kunne sende kodeord PASSORD til et bestemt telefonnummer, og få tilbake et garantert tilfeldig passord jeg kan bruke. Denne tjenesten er altså tiltenkt sikkerhetsfanatikere med dårlig fantasi.

toveis_sms

For å lage tjenesten vil jeg implementere en web service som jeg kan hoste i IIS. Tjenesten har to integrasjonspunkt: Ett SOAP-endepunkt må implementeres for å motta SMS-meldinger fra gateway'en, og i tillegg må tjenesten kalle en tilsvarende SOAP-tjeneste som gateway'en eksponerer når vi ønsker å sende melding tilbake til brukeren som ber om et passord.

For å lage en slik tjeneste trenger jeg produktet Gateway standard (produktark), og PSWinCom må registrere URLen til tjenesten min for kodeordet jeg vil bruke. Det er mulig å få demokonto for dem som ønsker å teste mulighetene. Det kan også være lurt a lage sin egen test-gateway (fakeway) om man vil teste tjenesten uten å nødvendigvis sende og motta SMS'er – det vil komme en egen blogpost om hvordan man enkelt kan gjøre dette.

Grensesnitt for innkommende meldinger

Å bruke SOAP-grensesnittet for mottak av SMS-meldinger i .Net er veldig enkelt. Først starter du Visual Studio Command Prompt, og bruker kommandoen wsdl for å generere et service interface.

Kommando for å generere SMS receive service interfaces:
wsdl /namespace:RandomPasswordService /serverInterface https://secure.pswin.com/SOAP/Receive.asmx?wsdl

Dette vil resultere i en fil som heter SMSReceiveInterfaces.cs. Den inneholder blant annet et interface som heter ISMSReceiveSoap. For å kunne ta imot meldinger må vi lage en web service som implementerer dette interfacet.

Grensesnitt for utgående meldinger

For å sende SMS-meldinger fra passord-tjenesten kan vi bruke et lite bibliotek, PSWinCom SMS Gateway Client for .NET, som kan lastes ned fra pswin.com. Om du ønsker å generere en SOAP proxy selv kan du gjøre det i stedet. All informasjon du trenger finner du i dokumentasjonen over grensesnittene.

RandomPasswordService-prosjektet

Jeg oppretter så et nytt ASP.NET Web Application prosjekt i Visual Studio som skal bli passord-tjenesten vår. Jeg sletter Default.aspx, og legger i stedet til SMSReceiverInterfaces.cs som jeg genererte, samt en referanse til PSWinCom.Gateway.Client.

Deretter legger jeg til en web service jeg kaller Password.asmx. Det er i denne servicen vi skal implementere interfacet for å håndtere innkommende meldinger. Til slutt legger jeg til en ny klasse-fil jeg kaller RandomDotOrg.cs hvor jeg vil implementere generering av passord, og rydder litt opp i dll-referansene.

CropperCapture[72]

Jeg er nå klar til å implementere tjenesten. I web servicen sin code behind sørger jeg først for å endre WebService namespace til http://pswin.com/SOAP/Receive (ikke glem dette!). Deretter sier jeg at Password skal arve fra ISMSReceiveSoap, og får Visual Studio til å generere stubs for metodene jeg trenger. Etter et par minutter er tjenesten ferdig:

    1 using System;
    2 using System.Web.Services;
    3 using PSWinCom.Gateway.Client;
    4 
    5 namespace RandomPasswordService
    6 {
    7     [WebService(Namespace = "http://pswin.com/SOAP/Receive")]
    8     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    9     [System.ComponentModel.ToolboxItem(false)]
   10     public class Password : WebService, ISMSReceiveSoap
   11     {
   12         #region ISMSReceiveSoap Members
   13 
   14         public ReturnValue ReceiveSMSMessage(IncomingSMSMessage m)
   15         {
   16             try
   17             {
   18                 Send(new Message
   19                 {
   20                     ReceiverNumber = m.SenderNumber, // return to sender
   21                     SenderNumber = m.ReceiverNumber,
   22                     Text = RandomDotOrg.GetNewPassword(),
   23                 });
   24             }
   25             catch { /* Log this !! */ }
   26             return new ReturnValue { Code = 200 };
   27         }
   28 
   29         public ReturnValue ReceiveDeliveryReport(DeliveryReport dr) {
   30             throw new NotImplementedException(); // not interested
   31         }
   32 
   33         public ReturnValue ReceiveMMSMessage(IncomingMMSMessage m) {
   34             throw new NotImplementedException(); // not interested
   35         }
   36         #endregion
   37 
   38         private void Send(Message message)
   39         {
   40             var smsClient = new SMSClient()
   41             {
   42                 Username = "",          // your Gateway username
   43                 Password = "",          // your Gateway passord
   44                 PrimaryGateway = "",    // the Gateway URL
   45                 SecondaryGateway = ""// backup Gatetway URL
   46             };
   47             smsClient.Messages.Add(0, message);
   48             smsClient.SendMessages();
   49         }
   50     }
   51 }

Metoden ReceiveSMSMessage kalles av gatewayen når det ankommer en ny melding. Interfacet har et par metoder til, for å ta imot meldingskvitteringer og MMS-meldinger, men de er jeg ikke interessert i her.

Jeg har laget en egen metode for å sende ut meldinger (linje 38), og det er her jeg bruker PSWinCom.Gateway.Client. Her kan du hente inn brukernavn, passord etc. fra konfigurasjonsfilen eller lignende.

Merk at jeg må returnere statuskode 200 fra ReceiveSMSMessage for å bekrefte at jeg klarte å ta imot meldingen. Hvis jeg ikke gjør dette vil gatewayen forsøke å sende meldingen på nytt (i henhold til definerte retry-regler).

Det er selvsagt mye som kan gjøres i forhold til feilhåndtering etc. Jeg ville normalt også inkludert endel logging. I tillegg kunne jeg ha benyttet meg av informasjonen i den innkommende meldingen, som hvilket kodeord som ble benyttet, eller hva den øvrige meldingsteksten var. Jeg kunne for eksempel lagt opp en mulighet for at brukerne kunne spesifisere hvor langt passordet skulle være ved å sende PASSORD n, hvor n er antall tegn.

Random passord

Det eneste som gjenstår er å implementere generering av passord. Til det vil jeg bruke en tjeneste som heter random.org, som gir meg ekte tilfeldighet, noe jeg ikke kan få til selv på windows. Her er GetNewPassord, som gjør et web-kall til random.org for å hente en random streng á 8 tegn.

    1 using System.Net;
    2 
    3 namespace RandomPasswordService
    4 {
    5     public static class RandomDotOrg
    6     {
    7         public static string GetNewPassword()
    8         {
    9             using (var webClient = new WebClient())
   10             {
   11                 return webClient
   12                     .DownloadString(
   13                     "http://www.random.org/strings/?" +
   14                     "num=1&len=8&digits=on&upperalpha=on" +
   15                     "&loweralpha=on&unique=on&format=plain&rnd=new")
   16                     .Trim();
   17             }
   18         }
   19     }
   20 }

(Merk at random.org har en quota per IP-adresse. Les guidelines for automated clients om du ønsker å benytte deg av random.org.)

Så der har du det altså, en komplett, toveis SMS-tjeneste i .Net / C# (som i tillegg kommuniserer med en ekstern tjeneste) på 71 linjer. Så hvis du har en god idé til en SMS-tjeneste bør du i alle fall ikke la kompleksiteten stopp deg, for så veldig mye enklere blir det ikke. 

Som nevnt skal jeg også skrive en artikkel om hvordan du kan teste tjenesten din uten å bruke PSWinCom's gateway, så følg med om du er interessert i det.

Relatert artikkel: Dagens sitat via SMS (énveis SMS m/Ruby og XML over TCP).


comments powered by Disqus