Отправка SMS через Web-сервис (CLR)

by Alexey Knyazev 19. января 2010 01:00

Кратко суть задачи: ГАРАНТИРОВАННАЯ отправка СМС-сообщений из уже существующих информационных систем, которые используются у нас на предприятии. Первое, что пришло в голову-это отправка через почту (e-mail to SMS) на ящик вида [номер абонента]@[адрес оператора] большинство сотовых операторов предоставляют подобную услугу (например у МТС: 7913ххххххх@sms.mtslife.ru), хоть и не гарантируют 100% доставку всех сообщений таким образом. После того, как объём сообщений, который стал генерить наш сервер, стал достаточно большим, часть сообщений стали "пропадать" либо приходить с большими задержками. Пришлось искать другое решение.

Идеальный вариант - это работа на прямую c СМС-сервером оператора по протоколу SMPP, но это дополнительная головная боль в виде подписания договора с операторами, которые предоставляют такую возможность для корпоративных клиентов и скорее всего - это дорогая услуга.

В качестве ещё одного варианта был поиск посредников, которые предоставляют подобные услуги. Выбор пал на ресурс http://sms-host.ru (не сочтите за рекламу). Они гарантируют доставку и отслеживание состояния СМС-сообщений через Веб сервис, но ПЛАТНО. Ну да ладно, попросили у них тестовый доступ и я сразу же загорелся идеей сделать CLR-сборку для работы с Веб сервисом.

Адрес Веб-сервиса: https://sms-host.ru/service/smshostws.asmx?WSDL.

Описание классов: http://www.sms-host.ru/docs/.

 

SumbitSm

Отправляет коллекцию одиночных сообщений

Test
The test form is only available for requests from the local machine.
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.

POST /service/smshostws.asmx HTTP/1.1
Host: sms-host.ru
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://sms-host.ru/SumbitSm"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <Authentication xmlns="http://sms-host.ru/">
      <User>string</User>
      <Password>string</Password>
    </Authentication>
  </soap:Header>
  <soap:Body>
    <SumbitSm xmlns="http://sms-host.ru/">
      <messageList>
        <WsSubmitSm ValidityPeriodSmpp="string" MessageText="string" SenderAddress="string" ReceiverAddress="string" MessageId="guid" />
        <WsSubmitSm ValidityPeriodSmpp="string" MessageText="string" SenderAddress="string" ReceiverAddress="string" MessageId="guid" />
      </messageList>
    </SumbitSm>
  </soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <SumbitSmResponse xmlns="http://sms-host.ru/">
      <SumbitSmResult>
        <WsSubmitSmResp ErrorDescription="string" ErrorCode="int" PartCount="unsignedByte" MessageId="guid" />
        <WsSubmitSmResp ErrorDescription="string" ErrorCode="int" PartCount="unsignedByte" MessageId="guid" />
      </SumbitSmResult>
    </SumbitSmResponse>
  </soap:Body>
</soap:Envelope>

 

QuerySm

Возвращает состояние сообщений, ранее отправленных с помощью метода SumbitSm

Test
The test form is only available for requests from the local machine.
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.

POST /service/smshostws.asmx HTTP/1.1
Host: sms-host.ru
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://sms-host.ru/QuerySm"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <Authentication xmlns="http://sms-host.ru/">
      <User>string</User>
      <Password>string</Password>
    </Authentication>
  </soap:Header>
  <soap:Body>
    <QuerySm xmlns="http://sms-host.ru/">
      <messageList>
        <WsQuerySm MessageId="guid" />
        <WsQuerySm MessageId="guid" />
      </messageList>
    </QuerySm>
  </soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <QuerySmResponse xmlns="http://sms-host.ru/">
      <QuerySmResult>
        <WsQuerySmResp EndTime="dateTime" BeginTime="dateTime" PartErrorCount="unsignedByte" PartDeliveredCount="unsignedByte" PartSendCount="unsignedByte" StateName="string" StateCode="int" MessageId="guid" />
        <WsQuerySmResp EndTime="dateTime" BeginTime="dateTime" PartErrorCount="unsignedByte" PartDeliveredCount="unsignedByte" PartSendCount="unsignedByte" StateName="string" StateCode="int" MessageId="guid" />
      </QuerySmResult>
    </QuerySmResponse>
  </soap:Body>
</soap:Envelope>

Как видно из документации, задача более чем тривиальная.

Приступим:

1) Создадим папку C:\SMS

2) Создаём прокси-сборку, запустив "

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl.exe" /o:SMSHost.cs /n:WS https://sms-host.ru/service/smshostws.asmx?WSDL

На выходе у нас получился файл SMSHost.cs

3) Немного изучив Веб-сервис, пишем нашу сборку, с 2мя функциями-отправка смс и получение состояния отправленного сообщения:

using System;
using Microsoft.SqlServer.Server;
using WS;

public class WSClass
{
            [SqlFunction]

    public static int SendMessage(string User, string Password, string SenderAddress, string ReceiverAddress, Guid MessageID, string ValidityPeriodSmpp, string Message)
    {

	WS.Authentication auth = new WS.Authentication();
            auth.User = User;
            auth.Password = Password;

	WS.WsSubmitSm s = new WS.WsSubmitSm();
            s.SenderAddress = SenderAddress;
            s.ReceiverAddress = ReceiverAddress;
	    s.MessageId = MessageID;
            s.ValidityPeriodSmpp = ValidityPeriodSmpp;
            s.MessageText = Message;

            WS.WsSubmitSm[] ss = new WS.WsSubmitSm[1];
            ss[0] = s;

	WS.SmsHostWs SendSMS=new WS.SmsHostWs();
	SendSMS.AuthenticationValue=auth;

	WS.WsSubmitSmResp Resp=new WS.WsSubmitSmResp();
	Resp=SendSMS.SumbitSm(ss)[0];

	return Resp.ErrorCode;
    }

  public static string MessageState(string User, string Password, Guid MessageID)
    {

	WS.Authentication auth = new WS.Authentication();
        auth.User = User;
        auth.Password = Password;

	WS.WsQuerySm q=new WS.WsQuerySm();
	q.MessageId=MessageID;

	WS.WsQuerySm[] qq = new WS.WsQuerySm[1];
        qq[0] = q;

	WS.SmsHostWs SendSMS=new WS.SmsHostWs();
	SendSMS.AuthenticationValue=auth;

	WS.WsQuerySmResp[] Resp = new WS.WsQuerySmResp[1];
        Resp[0]=SendSMS.QuerySm(qq)[0];

	return Resp[0].StateName;
    }

}

Сохраним этот текст в нашей папке в файл MyCLR.cs

4) Компилируем нашу библиотеку:

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CSC" /target:library /out:WSSMSHost.dll *.cs

На выходе файл WSSMSHost.dll

5) Создаем сборку сериализации XML:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sgen.exe" /a:WSSMSHost.dll

На выходе файл WSSMSHost.XmlSerializers.dll

Вроде бы ВСЁ. Дальше регистрируем наши библиотеки и пробуем отправить сообщения/прочитать их состояние.

CREATE ASSEMBLY ClrSMSHost
FROM 'C:\SMS\WSSMSHost.dll'
WITH PERMISSION_SET = UNSAFE;
GO

CREATE ASSEMBLY [ClrSMSHost.XmlSerializers]
FROM 'C:\SMS\WSSMSHost.XmlSerializers.dll'
WITH PERMISSION_SET = SAFE;
GO

Создаём функции:

CREATE FUNCTION [dbo].[SendMessage]
(
@User nvarchar(255),
@Password nvarchar(255),
@SenderAddress nvarchar(255),
@ReceiverAddress nvarchar(255),
@MessageID uniqueidentifier,
@ValidityPeriodSmpp nchar(16),
@Message nvarchar(max)
)
RETURNS [int] WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrSMSHost].[WSClass].[SendMessage]
GO

CREATE FUNCTION [dbo].[MessageState]
(
@User nvarchar(255),
@Password nvarchar(255),
@MessageID uniqueidentifier
)
RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrSMSHost].[WSClass].[MessageState]
GO

А теперь покажу как работать с этими функциями:

--Таблица для тестов
create table MyTable (MyID uniqueidentifier, Phone char(11), MyMessage nvarchar(50))
--Вставим всего 2 записи, для демонстрации
insert into MyTable
select NewID(), '7904ххххххх', 'Message1'
union all
select NewID(), '7904ххххххх', 'Message2'

Ну и отправим сообщения:

select  MyID, MyMessage, [dbo].[SendMessage] ('MyUser', 'MyPassword', 'SMS-Host.ru',
Phone, MyID, '000002233429000R', MyMessage)
from MyTable

где 'MyUser', 'MyPassword' - это логин и пароль на доступ к Веб сервису, а '000002233429000R' - время жизни сообщения (Время, в течение которого сервер будет пытаться отправить сообщение, если получатель недоступен. Если по истечении времени жизни сообщение все еще не доставлено, попытки доставки прекращаются и сообщение считается недоставленным.

Сообщение может стать недоставленным и до истечения времени жизни, если соответствующие сервисы оператора связи сообщили о невозможности доставки (например, номер получателя не существует). По умолчанию время жизни сообщения 2 суток с момента первой попытки отправки.), Для данного поля допустим только интервальный формат времени, то есть в форме YYMMDDhhmmsstnnR - Формат времени в стандарте SMPP v3.4.

Результат запроса: 

  1. BF23FCC4-00DD-4309-BF5A-AC4CAA22160E Message1 0
  2. 97063992-182E-4816-B648-35B8AE6FFBAE Message1 0

В ответе на запрос каждый элемент содержит атрибут ErrorCode Коды ошибок подразделяются на следующие категории:

Диапазон значений Категория

  • 0 Ошибок нет
  • 1-10 Текст сообщения не прошел проверку
  • 11-20 Номер получателя не прошел проверку
  • 21-30 Номер отправителя не прошел проверку
  • 31-40 Ошибки при постановке в очередь на отправку (например, если сообщение с таким идентфикатором уже отправлялось)

Отслеживать состояние сообщений можно запросом:

select MyID, [dbo].[MessageState] ('MyUser', 'MyPassword', MyID)
from MyTable

Результат запроса:

BF23FCC4-00DD-4309-BF5A-AC4CAA22160E	Сообщение доставлено
97063992-182E-4816-B648-35B8AE6FFBAE	Сообщение доставлено

 

Таким образом, практически на коленке, реализована задача…надеюсь кому-то этот пост будет полезен. Если у вас возникнут вопросы, то буду рад вам помочь.

Tags: , , , , ,

SQL Server

Добавить комментарий

  Country flag

biuquote
  • Комментарий
  • Предпросмотр
Loading