#c# #vb.net #ringcentral
#c# #vb.net #ringcentral
Вопрос:
Мне нужно отправлять SMS-сообщения с моего VB.net Приложение Windows Forms. В документации RingCentral приведен пример консольного приложения на C #, который довольно просто преобразовать в VB.net использование InstantVB. Приведенный ниже код работает, поскольку он является прямым переводом из их примера на C #, но это все еще консольное приложение. (О, и в их примере есть ошибка, которую я должен был исправить. Значение RINGCENTRAL_PRODUCTION должно быть логическим False, а не строкой «False», как показано в их примере.)
В любом случае… Я пытался запустить аналогичный код в приложении Windows Forms. Но, конечно, у меня нет подосновы для приложения Forms. Итак, я попытался поместить этот код в форму.Событие загрузки. Но когда это делается таким образом, оно всегда просто зависает в строке авторизации без сообщения об ошибке — оно просто зависает, пока я не нажму кнопку «пауза» (перерыв) в IDE.
Я работал над этим весь день, искал ответы в Интернете и был бы очень признателен за любые рекомендации.
Imports System
Imports System.Threading.Tasks
Imports RingCentral
Namespace Send_SMS
Friend Class Program
Private Const RECIPIENT As String = "9165551212"
Private Const RINGCENTRAL_CLIENTID As String = "_not_my_real_client_ID"
Private Const RINGCENTRAL_CLIENTSECRET As String = "_not_my_real_client_secret_"
Private Const RINGCENTRAL_PRODUCTION As Boolean = False
Private Const RINGCENTRAL_USERNAME As String = " 14245551212"
Private Const RINGCENTRAL_PASSWORD As String = "notarealpassword"
Private Const RINGCENTRAL_EXTENSION As String = "101"
Private Shared restClient As RestClient
Shared Sub Main(ByVal args() As String)
restClient = New RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION)
restClient.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD).Wait()
send_sms().Wait()
End Sub
Private Shared Async Function send_sms() As Task
Dim parameters = New CreateSMSMessage()
parameters.from = New MessageStoreCallerInfoRequest With {.phoneNumber = RINGCENTRAL_USERNAME}
parameters.to = New MessageStoreCallerInfoRequest() {
New MessageStoreCallerInfoRequest With {.phoneNumber = RECIPIENT}
}
parameters.text = "Hello World from VB.net" '< I changed that part.
Dim resp = Await restClient.Restapi().Account().Extension().Sms().Post(parameters)
Console.WriteLine("SMS sent. Message status: " amp; resp.messageStatus)
End Function
End Class
End Namespace
Просто для справки, ниже приведен оригинал на C # (с исправленной ошибкой):
using System;
using System.Threading.Tasks;
using RingCentral;
namespace Send_SMS
{
class Program
{
const string RECIPIENT = "9165551212";
const string RINGCENTRAL_CLIENTID = "_not_my_real_client_ID";
const string RINGCENTRAL_CLIENTSECRET = "_not_my_real_client_secret_";
const Boolean RINGCENTRAL_PRODUCTION = false;
const string RINGCENTRAL_USERNAME = " 14245551212";
const string RINGCENTRAL_PASSWORD = "notarealpassword";
const string RINGCENTRAL_EXTENSION = "101";
static RestClient restClient;
static void Main(string[] args)
{
restClient = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION);
restClient.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD).Wait();
send_sms().Wait();
}
static private async Task send_sms()
{
var parameters = new CreateSMSMessage();
parameters.from = new MessageStoreCallerInfoRequest { phoneNumber = RINGCENTRAL_USERNAME };
parameters.to = new MessageStoreCallerInfoRequest[] { new MessageStoreCallerInfoRequest { phoneNumber = RECIPIENT } };
parameters.text = "Hello World from C#";
var resp = await restClient.Restapi().Account().Extension().Sms().Post(parameters);
Console.WriteLine("SMS sent. Message status: " resp.messageStatus);
}
}
}
Комментарии:
1. почему вы поместили его в form_load? Конечно, вы действительно хотите отправить в ответ на что-то вроде нажатия кнопки?
2. На самом деле я также пытался вызвать его нажатием кнопки, с тем же результатом: зависание в строке авторизации. Я не был уверен, почему они отделили send_sms от кода в разделе Main, поэтому мой инстинкт заключался в том, что они хотели, чтобы RestClient (в более разработанном приложении) был «готов» к последующим вызовам send_sms. Я пробовал оба способа… все это вместе и как отдельные процедуры. Тот же результат.
3. Код должен вызываться после создания элементов управления формой. Элементы управления методом загрузки все еще создаются. Если вы хотите автоматически вызывать проект формы, создайте новый метод и поместите вызов в свой код в конце нового метода.
4. Я на самом деле также попытался поместить все это в событие нажатия кнопки с тем же результатом.
5. @jdweng я думаю, что ваш комментарий не совсем точен. Конструктор формы определенно вызывается перед загрузкой формы, и конструктор вызывает initComponent , а initComponent создает элементы управления…
Ответ №1:
Нет никакой волшебной разницы между приложением forms и консольным приложением..
Создайте новое приложение Forms (с единственной формой Form1, нажмите одну кнопку на форме и оставьте имя Button1 по умолчанию [но пообещайте мне, что измените его позже]), щелкните правой кнопкой мыши узел проекта в обозревателе решений и выберите Управление пакетами Nuget, найдите RingCentral.Чистый пакет и установите его
Вставьте этот код поверх всего в коде Form1.vb:
Imports RingCentral
Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
restClient = New RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION)
Await restClient.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD)
Await send_sms()
End Sub
Private Const RECIPIENT As String = "9165551212"
Private Const RINGCENTRAL_CLIENTID As String = "_not_my_real_client_ID"
Private Const RINGCENTRAL_CLIENTSECRET As String = "_not_my_real_client_secret_"
Private Const RINGCENTRAL_PRODUCTION As Boolean = False
Private Const RINGCENTRAL_USERNAME As String = " 14245551212"
Private Const RINGCENTRAL_PASSWORD As String = "notarealpassword"
Private Const RINGCENTRAL_EXTENSION As String = "101"
Private Shared restClient As RestClient
Private Shared Async Function send_sms() As Task
Dim parameters = New CreateSMSMessage()
parameters.from = New MessageStoreCallerInfoRequest With {.phoneNumber = RINGCENTRAL_USERNAME}
parameters.to = New MessageStoreCallerInfoRequest() {
New MessageStoreCallerInfoRequest With {.phoneNumber = RECIPIENT}
}
parameters.text = "Hello World from VB.net" '< I changed that part.
Dim resp = Await restClient.Restapi().Account().Extension().Sms().Post(parameters)
Console.WriteLine("SMS sent. Message status: " amp; resp.messageStatus)
End Function
End Class
Естественно, я получаю исключение, потому что детали в коде являются поддельными, но, по крайней мере, это ответ от службы!
Бонус: ожидание и задача 101:
Можно ожидать методы (функции / вспомогательные модули), которые возвращают задачи. Методы, содержащие await
ключевое слово, должны быть отмечены async
в теле их кода. Если вы запустите метод, который возвращает a Task(Of X)
, вы должны быстро получить Task(Of X)
ответ, пока среда выполнения начинает работать над задачей. Вы могли бы предположить, что прямо сейчас задача представляет собой пустой контейнер, который будет заполнен символом X, когда задача будет завершена. Если вы хотите X
, чтобы внутри него было что-то внутри, await
дождитесь завершения задачи, а затем извлеките из нее X для вас; «ожидание превращает задачу (из X) в X, когда X будет готов». В то время как поток вашей программы обрабатывает это await
, чтобы это произошло, он возвращается к тому, что он делал раньше (возможно, рисовал пользовательский интерфейс), что хорошо, потому что это выглядит так, как будто ваше приложение не зависало.
Обратите внимание, что это немного похоже на сохранение вашей компьютерной игры и выключение компьютера, когда друг заходит на кофе (задача, которая займет некоторое время) — друг уходит, вы возвращаетесь в игру, перезагружаете сохраненное состояние, и все остается как было. Ваша программа нажала ожидание, сохранила свою игру и ушла, чтобы сделать что-то еще. Когда задача была завершена, она вернулась, перезагрузила игру и продолжила с того места, где остановилась
Вы заметите, что задача (из X) имеет другие вещи, такие как свойство результата. Если вы получите доступ к нему вместо ожидания, ваша программа застрянет во время выполнения задачи, а затем вы получите свой X. В консольном приложении это, вероятно, не имеет значения, потому что консольное приложение, вероятно, не собиралось делать что-либо еще в промежуточный период, но приложение пользовательского интерфейса должно нарисовать свой пользовательский интерфейс, иначе Windows подумает, что оно не отвечает.
Я начинаю с Task(Of X)
того, что, вероятно, легче понять «задачу, которая выполняет что-то, что займет некоторое время, а затем дает мне то, что я хочу». Для методов, которые возвращают a Task
(т. Е. Не Выводят объект из задачи), вы просто Await
их, а затем они завершаются. Await
не извлекает какой-либо объект результата, потому что его нет, но ваша программа все еще смогла нарисовать свой пользовательский интерфейс. Вызов Wait()
задачи также будет ждать ее завершения, но при этом ваш пользовательский интерфейс будет загроможден
Комментарии:
1. Как вы, наверное, поняли, это работает. Просто хочу сказать спасибо, и я подумал, что уже несколько раз пробовал этот подход. (Поскольку я все еще немного не разбираюсь в Await и Task, это могло привести к моему первоначальному сбою методом проб и ошибок.) Я получаю галочку и голос вверх.
2. Добавлено немного внизу ответа, который, я надеюсь, поможет вам понять await / task