Before initializing a client using this SDK, you'll need three pieces of information:
- Your Project ID
- An access key ID
- An access key Secret
These values can be found on the Access Keys page of the Sinch Build Dashboard. You can also create new access key IDs and Secrets, if required.
If you have trouble accessing the above link, ensure that you have gained access to the Conversation API by accepting the corresponding terms and conditions.
Your app stores information such as your Sinch credentials as key-value pairs in the appsettings.Development.json file. This is much more flexible and secure than simply hardcoding them.
To set up your appsettings.Development.json file:
Open the
appsettings.Development.jsonfile.Paste the following JSON body into your
appsettings.Development.jsonfile."Sinch":{ "key_id":"", "key_secret":"", "project_id":"", "country_code_eu": "", "country_code_us": "", "from_number": "", "sms_region":"" },Populate the fields in the file with your own values. Refer to the table below for guidance:
Field Description key_idYour access key ID, used for authentication. Refer to the Client information section for more information. key_secretYour access key secret, used for authentication. Refer to the Client information section for more information. project_idYour project ID. Refer to the Client information section for more information. DEBUGSet to Trueto enable debugging.country_code_euIf you live in the EU or UK, this is the country code of your home country. For example the UK country code is +44.country_code_usIf you live in the US, this is the country code of your home country. For the US, it's +1.from_numberAny number you've assigned to your Sinch account. Find the number on your Customer Dashboard by clicking the service plan ID link and scrolling to the bottom of the page. sms_regionThe region in which you would like to send SMS messages. Either usoreu.
Global variables are stored in a static class. At your project's top level, create a file called Globals.cs. Paste in the following class:
using Sinch.SMS;
using Sinch.SMS.Groups;
public static class Globals
{
public static Group? SmsGroup {get; set;}
public static SmsRegion? region {get; set;}
}C#'s static keyword allows a variable to be accessed and modified without creating an instance of the class. Static classes function like bulletin boards. Methods in one class can "post" data to a global variable. This allows any other class to retreive and use it. Our application uses Globals to store the group and the SMS region.
Locate the Program.cs file and open it in an editor.
Add the following code above the line var app = builder.Build();:
// ensure you set the SMS region to your region.
Globals.region=Sinch.SMS.SmsRegion.Us;
builder.Services.AddSingleton<ISinchClient>(_ => new SinchClient(
builder.Configuration["Sinch:project_id"],
builder.Configuration["Sinch:key_id"],
builder.Configuration["Sinch:key_secret"],
options =>
{
options.SmsRegion = Globals.region;
options.LoggerFactory = LoggerFactory.Create(config => { config.AddConsole(); });
options.HttpClient = new HttpClient();
}));In .NET, Program.cs has the job of setting your application up and running it. The dependencies your application needs are created as services. These services will be fed into a Controller using Dependency Injection. The SDK client is initialized and added to Services as a singleton, meaning there can only be one instance of it.
Next, add the following code beneath var app = builder.Build();.
var sinch = app.Services.GetService<ISinchClient>();
var groupList = await sinch.Sms.Groups.List(new ListGroupsRequest{PageSize=30});
foreach(var group in groupList.Groups){
if(group.Name=="Sinch Pirates" && group.Size<=1){
Globals.SmsGroup=group;
}
}
if(Globals.SmsGroup==null){
Globals.SmsGroup = await sinch.Sms.Groups.Create(new CreateGroupRequest() { Name = "Sinch Pirates" });
}This code set's up the group. It contains validation which is designed to stop you creating hundreds of groups called "Sinch Pirates". It first retreives a list of the groups you have already created. It creates a new group only if there is no existing "Sinch Pirates" group that you created in a previous tutorial.
The controller contains the business logic of your application. This includes enabling recipients to subscribe/unsubscribe from the campaign group as well as enabling users to create campaigns and schedule them.
In the Controllers folder, create a file called CampaignController.cs. Then, copy the code in the right panel of this page and paste it into the file. We'll step through each section of code below.
This code imports the SDK functionality your app needs to update a group and send a reply. It also specifies the namespace the Controller is in:
using Microsoft.AspNetCore.Mvc;
using Sinch;
using Sinch.SMS.Groups.Update;
using Sinch.SMS.Batches.Send;
using Sinch.SMS.Hooks;
using DeliveryReport = Sinch.SMS.DeliveryReport;
using System.Text.Json;
namespace sinch_campaign_manager.Controllers;
public class CampaignController : Controller
{
}Now let's review the class members and constructor. Take a look at the following code, which defines the CampaignController class:
private readonly ILogger<CampaignController> _logger;
private readonly IConfiguration Configuration;
private readonly ISinchClient _sinchClient;
public CampaignController(ISinchClient sinchClient, ILogger<CampaignController> logger, IConfiguration configuration)
{
_logger = logger;
_sinchClient = sinchClient;
Configuration = configuration;
}The constructor's job is to set up your controller by initializing the CampaignController members. This includes the SDK client object, which will be used to send SMS messages, the flash messaging object, which will be used to display the flash messages. There is also a configuration object for reading config values and logger object for debugging.
This component of your application is the auto-subscribe function. If you've completed the User consent tutorial, you'll recognise this function pretty quickly. It listens for an incoming SMS and adds/removes a user as appropriate:
public async Task<IActionResult> Subscribe([FromBody] IncomingTextSms incomingSms)
{
var group = Globals.SmsGroup;
string fromNumber = incomingSms.From;
string toNumber = incomingSms.To;
string autoReply = "";
string inboundMessage = incomingSms.Body;
var numbers = await _sinchClient.Sms.Groups.ListMembers(group.Id);
if (!numbers.Contains(fromNumber) && inboundMessage == "SUBSCRIBE")
{
var request = await _sinchClient.Sms.Groups.Update(new UpdateGroupRequest
{
GroupId = group.Id,
Add = new List<string>() { fromNumber }
}
);
autoReply = $"Congratulations! You are now subscribed to {group.Name}. Text STOP to leave this group.";
}
else if (numbers.Contains(fromNumber) && inboundMessage == "STOP")
{
await _sinchClient.Sms.Groups.Update(new UpdateGroupRequest
{
GroupId = group.Id,
Remove = new List<string>() { fromNumber }
});
autoReply = $"We're sorry to see you go. You can always rejoin {group.Name} by texting \"SUBSCRIBE\" to {toNumber}";
}
else
{
autoReply = $"Thanks for your interest. If you want to subscribe to this group, text \"SUBSCRIBE\" to {toNumber}";
}
var response = await _sinchClient.Sms.Batches.Send(new SendTextBatchRequest
{
Body = autoReply,
DeliveryReport = DeliveryReport.None,
To = new List<string>() { fromNumber },
From = toNumber
});
_logger.LogInformation(JsonSerializer.Serialize(response, new JsonSerializerOptions()
{
WriteIndented = true
}));
return Ok();
}The next part of your application implements the business logic for campaign scheduling. Let's start with the ScheduleCampaign method, whose job is to send the SMS at a particular time.
public async void ScheduleCampaign(List<string> to, string message, DateTime reminder_datetime)
{
var response = await _sinchClient.Sms.Batches.Send(new Sinch.SMS.Batches.Send.SendTextBatchRequest
{
Body = message,
From = Configuration["Sinch:from_number"],
To = to,
SendAt = reminder_datetime,
DeliveryReport = Sinch.SMS.DeliveryReport.None
});
Console.WriteLine(JsonSerializer.Serialize(response, new JsonSerializerOptions()
{
WriteIndented = true
}));
}
If you've completed the Appointment Reminder tutorial, you'll see that this is similar to the RemindPatient function. It uses the SinchClient instance you created previously to call the SDK send method. What makes this method powerful is the SendAt parameter. Because the Sinch SMS REST API has message scheduling built in, it's a one-stop shop for any application that requires sending SMS messages at particular times. This removes any need for you to create task scheduling. Moreover, it means you don't need your app to be running all the time! In addition to SendAt, the send method has a number of other parameters, including message expiry and delivery reports. These are available on the REST API reference.
Now let's review the controller's business logic:
public async Task<IActionResult> Index()
{
return RedirectToAction(nameof(Submit));
}
public async Task<IActionResult> Submit()
{
return View();
}The
Indexmethod redirects from the root URL. This ensures that when users typehttp://localhost:5247/Appointmentand they will be taken to the appointment scheduling form athttp://localhost:5247/Appointment/Submit.The
Submitmethod displays the appointment scheduling form.
The third method contains the meat of of your application's business logic:
[HttpPost]
public async Task<IActionResult> Submit(string message, DateTime campaign_date, DateTime campaign_time)
{
System.Console.WriteLine("SUBMIT METHOD");
DateTime campaign_datetime = new DateTime(campaign_date.Year, campaign_date.Month, campaign_date.Day, campaign_time.Hour, campaign_time.Minute, campaign_time.Second);
TempData["campaign_datetime"] = campaign_datetime;
var now = DateTime.Now;
string country_code = "+1";
if (Globals.region==SmsRegion.Eu)
{
country_code = Configuration["Sinch:country_code_eu"];
}
string groupId = Globals.SmsGroup.Id;
var to = await _sinchClient.Sms.Groups.ListMembers(groupId);
DateTime send_at = campaign_datetime.ToUniversalTime();
ScheduleCampaign(to.ToList(), message, send_at);
return RedirectToAction(nameof(Success));
}You'll see it's pretty similar to the post method in the appointment reminder app. It receives form data from the front end and sends an SMS message by calling ScheduleCampaign. Once a confirmation message is sent, the user is redirected to the Success.cshtml page. The Sinch SDK requires phone numbers to have a country code, so Submit checks the SMS region and adds a US/EU country code to the phone number.
The final method renders the success page.
public IActionResult Success()
{
return View();
}Congratulations! That's the core of your application completed.