I am using Visual studio. This is for Asp.net web application (.net framework)
this solution as a webcore application is acceptable as well.
I would like to be able to enter the information for message and to phone number dynamically , but i dont know how to "pause" the program so that this can happen. I understand the dynamic part, and can use Javascript to do that,
Basically what I want is an app that brings up a webpage where the end user enters the to number and the message, and then clicks send to send.
I thought it would be simple, but not so much :(
I have the quick start code for C# as -
// Install the C# / .NET helper library from twilio.com/docs/csharp/install
using System;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
class Program
{
static void Main(string[] args)
{
// Find your Account Sid and Token at twilio.com/console
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "your_auth_token";
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: "Join Earth's mightiest heroes. Like Kevin Bacon.",
from: new Twilio.Types.PhoneNumber("+15017122661"),
to: new Twilio.Types.PhoneNumber("+15558675310")
);
Console.WriteLine(message.Sid);
}
}
Okay I'm going to assume you want to send SMS. Further, I'm going to assume you're using Asp.Net MVC. Twilio voice is a little bit more complex, as Twilio calls back several times to get voice scripts and update statuses. More complex if you need phone tree behavior.
SMS Callbacks happen more than once too, but they're calling the same callback URL over and over, nothing fancy there.
The flow should look like this:
Web interface -> Asp.Net MVC Controller Action -> Database -> Twilio
I'll leave the web interface to you, and give some examples of the backend stuff.
You'll want a database, with one table 'Message'
Message should have these columns (at a minimum, you may need more):
message_id_pk
twilio_sid (nullable)
message_content (160 character limit if you want to keep messages in one SMS segment, this has considerations on operating cost)
status (nullable)
recipient_phone
Controller Action:
[Authorize] //assuming you'll want to have users authenticate before they can send the sms
[RequireHttps]
public async Task<ActionResult> SendSMS(
[Bind(Include = "message_id_pk, message_content, recipient_phone"] Message message)
{
db.Messages.Add(message);
TwilioSmsSender.SendSMS(message);
return RedirectToAction("Success");
}
And in TwilioSender.cs
public static void SendSMS(Message message)
{
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "your_auth_token";
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: message.message_content,
from: new Twilio.Types.PhoneNumber("+15017122661"), //note: you can let your Twilio Messaging service handle the phone number, I recommend you look into that
to: new Twilio.Types.PhoneNumber(message.recipient_phone)
statusCallback: new Uri(TwilioCallBackController.SMSCallBackURL)
);
message.twilio_sid = message.Sid;
db.SaveChanges();
}
And in TwilioCallBackController.cs (You need to handle callbacks from Twilio here)
[ValidateTwilioRequest]
public ActionResult TwilioSMSCallback()
{
string sid = Request.Form["SmsSid"];
List<Message> msg = db.Message.Where(x=> x.twilio_sid == sid).ToListAsync();
if(msg.Count > 0)
{
Message message = msg.First();
message.status = Request.Form["SmsStatus"];
}
}
Related
Is it possible to implement a two-factor authentication without use ASP.NET Core Identity?
I have my own login table and everything works fine with login + password + jwt, but my customer wants to put a extra security using a two-factor authentication via SMS or E-mail.
I thought about Authy from Twilio but I don't understand if it is possible to do without ASP.NET Core Identity.
Twilio's Two Factor Authentication (2FA) services do not depend on the ASP.NET Core Identity framework, so you are not required to use it in combination with Identity, tho you can.
Before providing more details, I do want to get on the same page on Twilio's 2FA products to avoid confusion.
Twilio has a couple of 2FA products as explained in this comparison page:
Twilio Authy application: A free consumer application to generate Time-based One-Time Passwords (TOTP).
Twilio Authy API: An API for developers to integrate 2FA into your applications. The Twilio Verify API superseeds the Twilio Authy API.
Twilio Verify API: An API for developers to integrate 2FA into your applications. Verify API has an improved developer experience and supports more channels than the Authy API.
Twilio recommends using the Verify API for new development, so I'll be using the Verify API for this answer, however, let me know if you need a Authy API sample for some reason.
You can add the Twilio Verify API to any application, for example, here's a console application to verify a phone number:
string accountSid = configuration["Twilio:AccountSid"];
string authToken = configuration["Twilio:AuthToken"];
string verificationServiceSid = configuration["Twilio:VerifyServiceSid"];
TwilioClient.Init(accountSid, authToken);
Console.Write("What is your phone number? ");
string phoneNumber = Console.ReadLine();
var verification = await VerificationResource.CreateAsync(
to: phoneNumber,
channel: "sms",
pathServiceSid: verificationServiceSid
);
Console.WriteLine("Verification status: {0}", verification.Status);
Console.Write("Enter the code texted to your phone: ");
string code = Console.ReadLine();
var verificationCheck = await VerificationCheckResource.CreateAsync(
verificationSid: verification.Sid,
code: code,
pathServiceSid: verificationServiceSid
);
Console.WriteLine("Verification status: {0}", verificationCheck.Status);
The configuration comes from the ConfigurationBuilder which you can learn more about here.
You can find the Twilio:AccountSid and Twilio:AuthToken in the Twilio Console.
To use the Verify API, you need to create a Verify Service, which you can also do in the Twilio Console (or using the API, SDK, or CLI).
The Verify Service will have an String Identifier (SID) which I'm storing in Twilio:VerifyServiceSid.
Once the program has the necessary Twilio configuration, it'll initialize the TwilioClient, then it'll ask the user for a phone number to verify, then it uses the phone number to create a VerificationResource.
When this VerificationResource is created, Twilio will send a code to the phone number.
The program will ask for that code and then use the code to create the VerificationCheckResource.
The status of the created VerificationCheckResource will indicate whether the code was correct.
Status can have three different string values:
pending: This is the default status, but also the status when a code was provided, but not the correct code.
approved: The provided code was correct, the phone number is verified.
cancelled: The verification has been cancelled, you can create a new verification to start over.
This example uses SMS as a channel, but the flow is more or less the same for other channels.
The above sample merged the samples from the Twilio Docs on Verify for C#.
You can now apply the same logic into your ASP.NET Core applications as you see fit.
Here's an example of an ASP.NET Core MVC controller with some actions and views to verify a phone number via SMS.
HomeController.cs:
using Microsoft.AspNetCore.Mvc;
using Twilio.Rest.Verify.V2.Service;
using TwilioVerifyAspNet.Models;
public class HomeController : Controller
{
private readonly string verifyServiceSid;
public HomeController(IConfiguration configuration)
{
verifyServiceSid = configuration["Twilio:VerifyServiceSid"];
}
[HttpGet]
public IActionResult Index() => View();
[HttpGet]
public IActionResult RequestTwoFactorToken() => View();
[HttpPost]
public async Task<IActionResult> RequestTwoFactorToken(RequestTwoFactorViewModel requestTwoFactorViewModel)
{
if (!ModelState.IsValid)
{
return View(requestTwoFactorViewModel);
}
var verificationResource = await VerificationResource.CreateAsync(
to: requestTwoFactorViewModel.PhoneNumber,
channel: "sms",
pathServiceSid: verifyServiceSid
);
var verifyTwoFactorViewModel = new VerifyTwoFactorViewModel
{
VerificationSid = verificationResource.Sid,
Code = null
};
return View("VerifyTwoFactorToken", verifyTwoFactorViewModel);
}
[HttpPost]
public async Task<IActionResult> VerifyTwoFactorToken(VerifyTwoFactorViewModel verifyTwoFactorViewModel)
{
if (!ModelState.IsValid)
{
return View(verifyTwoFactorViewModel);
}
var verificationCheck = await VerificationCheckResource.CreateAsync(
verificationSid: verifyTwoFactorViewModel.VerificationSid,
code: verifyTwoFactorViewModel.Code,
pathServiceSid: verifyServiceSid
);
switch (verificationCheck.Status)
{
case "pending":
verifyTwoFactorViewModel.Status = "pending";
return View("VerifyTwoFactorToken", verifyTwoFactorViewModel);
case "canceled":
verifyTwoFactorViewModel.Status = "canceled";
return View("VerifyTwoFactorToken", verifyTwoFactorViewModel);
case "approved":
return View("Success");
}
return View("VerifyTwoFactorToken", verifyTwoFactorViewModel);
}
}
RequestTwoFactorViewModel.cs:
using System.ComponentModel.DataAnnotations;
public class RequestTwoFactorViewModel
{
[Required]
public string PhoneNumber { get; set; }
}
VerifyTwoFactorViewModel.cs:
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding;
public class VerifyTwoFactorViewModel
{
[Required]
public string? VerificationSid { get; set; }
[Required]
public string? Code { get; set; }
// prevent user from setting the status via form
[BindNever]
public string? Status { get; set; }
}
RequestTwoFactorToken.cshtml:
#model RequestTwoFactorViewModel
<form asp-controller="Home" asp-action="RequestTwoFactorToken">
<label for="phone-number">Phone Number</label> <br>
<input id="phone-number" asp-for="PhoneNumber"/> <br>
<button type="submit">Submit</button>
</form>
VerifyTwoFactorToken.cshtml:
#model VerifyTwoFactorViewModel
#if (Model.Status == null || Model.Status == "pending")
{
<form asp-controller="Home" asp-action="VerifyTwoFactorToken">
<input type="hidden" asp-for="VerificationSid" />
<label for="code">Code</label> <br>
<input id="code" asp-for="Code"/> <br>
<button type="submit">Submit</button>
</form>
}
else if (Model.Status == "cancelled")
{
<text>Your 2FA verification has been cancelled</text>
}
You do have to make sure you initialize the TwilioClient at startup of your application.
The RequestTwoFactorToken HTTP GET action will render a form to ask for the phone number.
When the form is submitted, the RequestTwoFactorToken HTTP POST action will create the VerifyResource, which is used to create the VerifyTwoFactorViewModel to render the VerifyTwoFactorToken.cshtml view. The VerifyTwoFactorToken.cshtml view asks the user for the SMS code.
When this form is submitted, the VerifyTwoFactorToken action will create a VerificationCheckResource. The resulting status is evaluated to see whether the code was correct or not.
This is a sample and by no means production ready, but it contains all the pieces you need to implement this into your own application.
Hopefully this helps, I can't wait to see what you build!
I'm trying to use Twilio to connect workers through a kind of Walkie Talkie (all the workers get a JWT to make browser calls using the Javascript SDK), for this I use the Twiml verb conference, when the worker press the conference button in the browser it sends a list of the active workers (except for the one who started the conference), I use the callSid as the name of the conference to make it unique and the CallResource to put every worker into the conference.
However, the workers in the list start listening the wait music for a conference room, but the caller automatically end the connection as soon as it is open, it doesn't even ends the conference, I don't know what's wrong with the code, I'm following the documentation for conferences in https://www.twilio.com/docs/voice/twiml/conference
Here is the method that's called when a conference needs to be created:
public VoiceResponse ConferenceTalk(List<string> recipients, string caller, string callSid)
{
TwilioClient.Init(my_account_sid, my_auth_token);
var confName = $"wt_{callSid}";
foreach (var recipient in recipients)
{
CallResource.Create(
url: new Uri($"{this.publicUrl}/Conference/WtConference/{confName}"),
to: new Twilio.Types.Client($"client:{recipient}"),
from: new Twilio.Types.Client(caller));
}
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName,
startConferenceOnEnter: true,
endConferenceOnExit: true);
response.Append(dial);
return response;
}
Here is the endpoint the CallResource target with the url attribute:
[HttpPost]
public TwiMLResult WtConference()
{
var confName = Request.Url.Segments[Request.Url.Segments.Length - 1];
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName);
response.Append(dial);
return TwiML(response);
}
I feel like the time all of this takes to happen might be causing your issues here. And the Twilio Voice SDK may not be the best product for this. I'd have to see maybe a video showing how the interaction works to fully commit to this.
In the meantime, I might try to speed up people joining the conference by sending the TwiML for the conference in the API call, not waiting for the webhook. e.g.:
public VoiceResponse ConferenceTalk(List<string> recipients, string caller, string callSid)
{
TwilioClient.Init(my_account_sid, my_auth_token);
var confName = $"wt_{callSid}";
var outboundResponse = new VoiceResponse();
var outboundDial = new Dial();
outboundDial.Conference(confName);
outboundResponse.Append(outboudDial);
foreach (var recipient in recipients)
{
CallResource.Create(
twiml outboundResponse,
to: new Twilio.Types.Client($"client:{recipient}"),
from: new Twilio.Types.Client(caller));
}
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference(confName,
startConferenceOnEnter: true,
endConferenceOnExit: true);
response.Append(dial);
return response;
}
I say that Twilio Voice might not be best for this because on the Twilio back end, this is going through a whole stack that is built for making phone calls. Outbound calls are made at a rate of 1 call per second, so that might be slowing the calling of your list down.
You could consider the Twilio Video SDK for this instead (you can make audio only calls with the Twilio Video product). For this you would need to be able to trigger each of workers joining a room that was then used to distribute the audio. There aren't limits on calls per second, workers would just need to connect to a room and your application would be able to control who could talk at any one time.
BACKGROUND
currently I am in a side project where I am building a Xamarin based mobile App for easy movie and tv show searching and navigation based on user preferences (e.g. based on movie genre etc).
To do this the mobile app acts as a client to the https://www.themoviedb.org/documentation/api online movie database's Web API service.
PROBLEM
I am looking for an easy and well supported package to wrap API Uri paths and query parameters into a web api query. I have looked a bit on RestSharp .
I like the syntax very much with the pattern based query path:
var request = new RestRequest("resource/{id}");
request.AddParameter("name", "value");
request.AddUrlSegment("id", "123");
but I am not sure about the packages future. Also if there is an alternative from MS, I would take that.
So have also looked Web-API tailored at MS alternatives but I am unsure what is recommended there. I only can find docs and examples for the server side (ASP.NET CORE MVC).
I need to be pointed to a well functioning .NET Standard 2.0 package from Microsoft or from a 3rd party to send Web API request from my Xamarin client.
Where am I
I have already written a lot of code based on pure HttPClient and AspNetcore.WebUtilituies for assembling a query string. But the gazillions of API path segments are getting out of my hand. I really need something to manage API path templates like RestSharp does
Code sample:
here I declare all of the path segments which I assemble manually ==> ugly AF
public static class WebApiPathConstants
{
public const string BASE_Address = "https://api.themoviedb.org";
public const string BASE_Path = "/3";
public const string CONFIG_Path = "/configuration";
public const string GENRE_LIST_Path = "/genre/movie/list";
...
lot of lines here
....
public const string PAGE_Key = "page";
public const string INCLUDE_Adult_Key = "include_adult";
public const string API_KEY_Key = "api_key";
public const string RECOMMENDATIONS_Path = "/recommendations";
public const string SIMILARS_Path = "/similar";
}
Here I assemble a query and kick of a task to get movie details based on the query from the server: The assembly of the Url path is my main problem. It looks too error prone.
public async Task<FetchMovieDetailsResult> FetchMovieDetails(int id, string language = null, int retryCount = 0, int delayMilliseconds = 1000)
{
string baseUrl = BASE_Address + BASE_Path + MOVIE_DETAILS_Path + "/" + id;
var query = new Dictionary<string, string>();
query.Add(API_KEY_Key, apiKeyValue);
if (!string.IsNullOrEmpty(language))
query.Add(LANGUAGE_Key, language);
string requestUri = QueryHelpers.AddQueryString(baseUrl, query);
FetchMovieDetailsResult result = await GetResponse<FetchMovieDetailsResult>(retryCount, delayMilliseconds, requestUri);
return result;
}
The result is a POCO class with the HttpStatusCode and (if successful ) a Json object. The client accesses the Json object only if the StatusCode == 2xx.
Prepared to be shot down in flames here, if this doesn't match your use-case, but it looks like the TheMovieDb site itself has a list of client libraries. It's available here: https://www.themoviedb.org/documentation/api/wrappers-libraries. They're obviously a layer higher than you're asking for here, in that they completely wrap the API, such that you need not even know what you're calling or how you're calling it, but in the interests of getting the job done, they seem like they'd do the trick.
I know how to send targeted messages from the various tutorials with code like that:
// Get the current user SID and create a tag for the current user.
var claimsPrincipal = this.User as ClaimsPrincipal;
string sid = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier).Value;
string userTag = "_UserId:" + sid;
// Build a dictionary for the template with the item message text.
var notification = new Dictionary { { "message", item.Text } };
// Send a template notification to the user ID.
await hub.SendTemplateNotificationAsync(notification, userTag);
But I struggle to figure out how to send to all my registered UserIds.
I hope there is some method like:
// Send a template notification to all UserIds
await hub.SendTemplateNotificationAsync(notification);
Yes, there's an overload of SendTemplateNotificationAsync that looks exactly as you described:
public Task<NotificationOutcome> SendTemplateNotificationAsync(
IDictionary<string, string> properties)
Does it not work for you?
An alternative would be to register your users with an additional tag (e.g. "registered user" for all users or "paid user"/"trial user" if you need to slice them somehow) and then use the method you're currently using to send messages, but to this broader tag.
I am building an application where a user will call my Twilio Number. After connecting, Twilio will call another user and connect the two parties. However, the number displayed for the second party should be Twilio's number (or no caller ID), not the user's number.
I tired adding SIP header such as privacy = full & p-asserted-identity="anonymous" but none is working.
Code I am using for the callback:
[HttpPost]
public async Task<ActionResult> Connect(string from, string to)
{
//var outgoingPhoneNumber = await GatherOutgoingPhoneNumberAsync(from, to);
var response = new TwilioResponse();
response.Say("Please wait while we contact the other party");
response.Dial("+14085993263", new { });
return TwiML(response);
}
Is there anyway to do that?
Twilio developer evangelist here.
You're very close to the solution, but what want to do is add a callerid attribute to the Dial verb. That way, you can either add your Twilio number, or your own business' verified number. To do that just change your code to the following:
[HttpPost]
public async Task<ActionResult> Connect(string from, string to)
{
var response = new TwilioResponse();
response.Say("Please wait while we contact the other party");
response.Dial("+14085993263", new { callerId = "+1234567890" });
return TwiML(response);
}
Make sure you replace callerId with the number you wish to use. The caller ID can only be one of your Twilio numbers or a verified number as stated above.
Hope this helps you