Статьи

Windows Azure, SignalR & Twilio: телефонный звонок из облака

В предыдущем сообщении в блоге мы увидели, как вы можете отправлять электронные письма из Windows Azure. Почему бы не пойти дальше и сделать телефонный звонок из Windows Azure? Я уже упоминал, что Windows Azure — это платформа, которая будет запускать ваш код, дополненный каким-то потрясающим соусом в виде большого количества компонентов, которые ускорят разработку. Одним из таких компонентов является API, предоставляемый сторонней службой Twilio .

Twilio — это API-интерфейс веб-службы телефонии, который позволяет использовать имеющиеся у вас веб-языки и навыки для создания голосовых и SMS-приложений. Twilio Voice позволяет вашим приложениям совершать и принимать телефонные звонки. Twilio SMS позволяет вашим приложениям создавать и получать SMS-сообщения. Мы будем использовать Twilio Voice в сочетании с jQuery и SignalR для ускорения процесса регистрации.

Сценарий

Идея проста: мы хотим, чтобы пользователи регистрировались, используя имя пользователя и пароль. Кроме того, они должны будут предоставить свой номер телефона. Пользователь отправит форму регистрации и отобразит код подтверждения. В фоновом режиме пользователю позвонят и попросят ввести этот код подтверждения, чтобы подтвердить свой номер телефона. После завершения браузер автоматически продолжит процесс регистрации. Вот визуал:

clip_image002

Звучит слишком хорошо, чтобы быть правдой? Будьте готовы, так как это довольно просто, используя Windows Azure и Twilio.

Давайте начнем…

Прежде чем мы начнем, убедитесь, что у вас есть учетная запись Twilio . Twilio предлагает несколько бесплатных кредитов, которых достаточно для тестирования. После регистрации убедитесь, что вы разрешаете международные звонки и ваш номер телефона зарегистрирован как разработчик. Twilio делает этот шаг, чтобы убедиться, что их сервис не используется для совершения оскорбительных телефонных звонков с использованием бесплатных учетных записей разработчиков.

Затем создайте проект Windows Azure, содержащий веб-роль ASP.NET MVC 4. Установите в него следующие пакеты NuGet (щелкните правой кнопкой мыши «Диспетчер пакетов библиотеки»).

  • JQuery
  • jQuery.UI.Combined
  • jQuery.Validation
  • json2
  • Modernizr
  • SignalR
  • Twilio
  • Twilio.Mvc
  • Twilio.TwiML

Также может быть полезно развить некоторое знакомство с концепциями, стоящими за SignalR .

Регистрационная форма

Давайте создадим нашу форму. Используя простой класс модели SignUpModel , создайте следующий метод действия:

public ActionResult Index()
{
    return View(new SignUpModel());
}

Этот метод действия сопровождается представлением, простой формой, запрашивающей необходимую информацию у нашего пользователя:

@using (Html.BeginForm("SignUp", "Home", FormMethod.Post)) {
    @Html.ValidationSummary(true)
 
    <fieldset>
        <legend>Sign Up for this awesome service</legend>
 
         @* etc etc etc *@
 
        <div class="editor-label">
            @Html.LabelFor(model => model.Phone)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Phone)
            @Html.ValidationMessageFor(model => model.Phone)
        </div>
 
        <p>
            <input type="submit" value="Sign up!" />
        </p>
    </fieldset>
}

Сначала мы добавим эту форму в диалог. Используя пользовательский интерфейс jQuery, мы можем создать простой элемент <div>, который будет служить содержимым диалога. Обратите внимание на класс ui-helper-hidden, который используется, чтобы сделать его невидимым для просмотра.

<div id="phoneDialog" class="ui-helper-hidden">
    <h1>Keep an eye on your phone...</h1>
    <p>Pick up the phone and follow the instructions.</p>
    <p>You will be asked to enter the following code:</p>
    <h2>1743</h2>
</div>

Это простой диалог, в котором мы покажем жестко закодированный код подтверждения, который пользователь должен будет предоставить при вызове с использованием Twilio.

Далее, давайте закодируем нашу логику JavaScript, которая оживит эту форму. Сначала добавьте необходимые библиотеки JavaScript для SignalR (подробнее об этом позже):

<script src="@Url.Content("~/Scripts/jquery.signalR-0.5.0.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/signalr/hubs")" type="text/javascript"></script>

Затем, захватите событие отправки формы и, если номер телефона еще не был подтвержден, отмените событие отправки и покажите наш диалог:

$('form:first').submit(function (e) {
    if ($(this).valid() && $('#Phone').data('validated') != true) {                
        // Show a dialog
        $('#phoneDialog').dialog({
            title: '',
            modal: true,
            width: 400,
            height: 400,
            resizable: false,
            beforeClose: function () {
                if ($('#Phone').data('validated') != true) {
                    return false;
                }
            }
        });
                
        // Don't submit. Yet.
        e.preventDefault();
    }
});

Ничего особенного пока нет. Если вы сейчас запустите этот код, вы увидите, что диалоговое окно открывается и остается открытым вечно. Давайте создадим некоторый код SignalR сейчас. SignalR использует концепцию Hubs для обеспечения связи клиент-сервер, а также взаимодействия сервер-клиент. Нам понадобится последний, чтобы сообщить нашему мнению, когда пользователь подтвердил свой номер телефона. В проекте добавьте следующий класс:

[HubName("phonevalidator")]
public class PhoneValidatorHub
    : Hub
{
    public void StartValidation(string phoneNumber)
    {
    }
}

Этот класс определяет сервис, который может вызвать клиент. SignalR также будет держать соединение с клиентом открытым, чтобы этот PhoneValidatorHub мог позже отправить сообщение клиенту. Давайте подключим наш взгляд к этому хабу. В обработчике отправки формы добавьте следующую строку кода:

// Validate the phone number using Twilio
$.connection.phonevalidator.startValidation($('#Phone').val());

Мы создали класс C # с методом StartValidation и вызываем сообщение startValidation из JavaScript. Стечение обстоятельств? Нет. SignalR делает это возможным. Но мы еще не закончили. Теперь мы можем вызвать метод на стороне сервера, но как сервер сообщит клиенту, когда номер телефона был подтвержден? Я вернусь к этому позже. Во-первых, давайте удостоверимся, что наш код JavaScript может получать этот вызов с сервера. Для этого подключитесь к хабу PhoneValidator и добавьте к нему функцию обратного вызова:

var validatorHub = $.connection.phonevalidator;
validatorHub.validated = function (phoneNumber) {
    if (phoneNumber == $('#Phone').val()) {
        $('#Phone').data('validated', true);
        $('#phoneDialog').dialog('destroy');
        $('form:first').trigger('submit');
    }
};
$.connection.hub.start();

Здесь мы добавляем клиентскую функцию с именем validated в концентратор SignalR. Мы можем вызвать эту функцию, сидя на стороне клиента, из нашего кода на стороне сервера позже. Сама функция проста: она проверяет, совпадает ли проверенный телефонный номер с введенным пользователем, и, если это так, отправляет форму и завершает регистрацию.

Осталось только позвонить пользователю, и, когда подтверждение прошло успешно, мы должны будем сообщить нашему клиенту, вызвав проверенное сообщение в концентраторе.

Инициирование телефонного звонка

Телефонный звонок нашему пользователю будет инициирован с помощью метода StartValidation в PhoneValidatorHub . Добавьте туда следующий код:

var twilioClient =new TwilioRestClient("api user", "api password");
 
string url ="http://mas.cloudapp.net/Home/TwilioValidationMessage?passcode=1743"+"&phoneNumber="+ HttpContext.Current.Server.UrlEncode(phoneNumber);
 
// Instantiate the call options that are passed to the outbound callCallOptions options =new CallOptions();
options.From ="+14155992671"; // Twilio's developer number options.To = phoneNumber;
options.Url = url;
 
// Make the call.twilioClient.InitiateOutboundCall(options);

Используя класс TwilioRestClient , мы создаем запрос к Twilio. Мы также передаем URL, который указывает на наше приложение. Twilio использует TwiML, формат XML для инструктирования своих телефонных служб. При вызове метода InitiateOutboundCall Twilio отправит запрос на URL-адрес, который мы размещаем ( http: //…..cloudapp.net/Home/TwilioValidationMessage ), чтобы получить TwiML, который сообщает Twilio, что нужно сказать, попросить, записать, собери … по телефону.

Далее: реализация метода действий TwilioValidationMessage .

public ActionResult TwilioValidationMessage(string passcode, string phoneNumber)
{
    var response = new TwilioResponse();
    response.Say("Hi there, welcome to Maarten's Awesome Service.");
    response.Say("To validate your phone number, please enter the 4 digit"
        + " passcode displayed on your screen followed by the pound sign.");
    response.BeginGather(new {
        numDigits = 4,
        action = "http://mas.cloudapp.net/Home/TwilioValidationCallback?phoneNumber="
             + Server.UrlEncode(phoneNumber), method = "GET" });
    response.EndGather();
 
    return new TwiMLResult(response);
}

Это правильно. Мы создаем здесь TwiML . Наш метод действия ASP.NET MVC говорит Twilio сказать какой-нибудь текст и собрать 4 цифры со своей телефонной панели. Эти 4 цифры будут опубликованы в методе действий TwilioValidationCallback службой Twilio. Какой следующий метод мы должны реализовать?

public ActionResult TwilioValidationCallback(string phoneNumber)
{
    var hubContext = GlobalHost.ConnectionManager.GetHubContext<PhoneValidatorHub>();
    hubContext.Clients.validated(phoneNumber);
 
    var response = new TwilioResponse();
    response.Say("Thank you! Your browser should automatically continue. Bye!");
    response.Hangup();
 
    return new TwiMLResult(response);
}

TwilioValidationCallback метод действия делает две вещи. Сначала он получает ссылку на наш концентратор SignalR и вызывает на нем проверенную функцию. Как вы помните, мы создали этот метод на стороне клиента концентратора, поэтому фактически наше серверное приложение ASP.NET MVC вызывает метод на стороне клиента. Это заставляет клиента скрывать диалоговое окно проверки и завершать процесс регистрации пользователя.

Еще одно действие, которое мы здесь делаем, — это создание еще одного TwiML (это весело!). Мы благодарим пользователя за подтверждение его номера телефона, и после этого мы вешаем трубку.

Вы видите? Работать с голосом (и текстовыми сообщениями, если хотите) тоже не сложно. Это позволяет использовать дополнительные сценарии, которые могут выделить ваше приложение среди множества других. Наслаждайтесь!

05 ConfirmPhoneNumberDemo.zip (1,32 МБ)