Creating a user consent application using the .NET SDK
Creating the application
We're now going to create the core of our user consent application. Because this is an MVC project, we'll need three components (and files) to make it work.
Program.cs
will contain code necessary for application setup. This includes initializing the Sinch SDK client and creating the group.InboundController.cs
will contain theSubscribe
method that listens for an inbound message and subscribes/unsubscribes the message sender from the group. Because this file is the most complex, the completed code is displayed on the right panel.- Once the group is created, the
Globals
static class (found in theGlobals.cs
folder) will shuttle it to the Controller where it can be accessed and modified.
Note:
For the purposes of this tutorial, we are creating a group as part of initializing the user consent application. In the real world, however, your app would probably use a preexisting group, so there would be no need for this step.
Program.cs
First, we'll add the application setup. This involves initializing the SDK client and creating the group, and is done in theProgram.cs
file. Open that file and replace its contents with the following code:using Sinch;
using Sinch.SMS.Groups.List;
using Sinch.SMS.Groups.Create;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddSingleton<ISinchClient>(_ => new SinchClient(
"YOUR_project_id",
"YOUR_access_key",
"YOUR_access_secret",
options =>
{
options.SmsRegion = Sinch.SMS.SmsRegion.Eu;
options.LoggerFactory = LoggerFactory.Create(config => { config.AddConsole(); });
options.HttpClient = new HttpClient();
}));
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" });
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Initializing the client
The above snippet includes code to intialize the client.
To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard.
Note:
For testing purposes on your local environment it's fine to use hardcoded values, but before deploying to production we strongly recommend using environment variables to store the credentials.
using Sinch;
var sinch = new SinchClient("YOUR_project_id",
"YOUR_access_key",
"YOUR_access_secret");
SinchClient
is thread safe, so it's fine to add it as a singleton:builder.Services.AddSingleton<ISinchClient>(x => new SinchClient(
builder.Configuration["YOUR_project_id"],
builder.Configuration["YOUR_access_key"],
builder.Configuration["YOUR_access_secret"]));
SmsRegion
is set correctly. The code has it set to Eu
, but you can update that value to Us
if you are located in the United States.Creating the group
The group is created beneathvar 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 contains validation which prevents the creation of 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.
InboundController.cs
Now we'll review theInboundController.cs
file. This is the centerpeice of our application and contains the auto subscribe method. To add this file:- Navigate into the
Controllers
folder. - Create a file called
InboundController.cs
. - Copy the completed code is displayed on the right panel and paste the contents into the
InboundController.cs
file.
We'll step through each section of that code below.
Adding imports
The code begins by adding the following imports:
using Microsoft.AspNetCore.Mvc;
using Sinch;
using Sinch.SMS.Groups.Update;
using Sinch.SMS.Batches.Send;
using Sinch.SMS.Hooks;
using System.Text.Json;
namespace SinchUserConsent.Controllers;
public class InboundController : ControllerBase
{
}
This imports the SDK functionality your app needs to update a group and send a reply. It also specifies the namespace the Controller is in.
The InboundController
class
Then, we create the class members and constructor. Below is the code that represents the InboundController
class:private readonly ISinchClient _sinchClient;
private readonly ILogger<InboundController> _logger;
public InboundController(ISinchClient sinchClient, ILogger<InboundController> logger)
{
_sinchClient = sinchClient;
_logger = logger;
}
There are two members, the SDK client and a logger object for debugging. They are both initialized in the constructor.
The Subscribe
method
Then, we have the Subscribe
method: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}";
}
}
This is similar to the app in the Receive an SMS Message guide. Its basic job is to listen for an inbound message and respond with an action. However, where the Receive Message app simply returned a reply containing the inbound message, the user consent app contains relatively complex business logic to handle incoming requests appropriately.
The logic is designed to cover the following basic contingencies:
- If a user is not already a group member and wants to join, the app looks for the SUBSCRIBE keyword. It then uses the SDK
update
method to add them to the group and assigns a confirmation message to the variableautoReply
. - When a user is already a group member and wants to leave, the app looks for the STOP keyword. It then uses the SDK
update
method to remove them from the group and assigns a confirmation message to the variableautoReply
. - If a user is not a group member but doesn't know the keyword to join, the application sends a message thanking them and telling them the right keyword.
The Send
method
Finally, we include the Send
method in the the InboundController.cs
file:var response = await _sinchClient.Sms.Batches.Send(new SendTextBatchRequest
{
Body = autoReply,
DeliveryReport = Sinch.SMS.DeliveryReport.None,
To = new List<string>() { fromNumber },
From = toNumber
});
Subscribe
method processes an inbound request, it assigns a confirmation message to the autoReply
variable. The Send
method takes the value of autoReply
and sends it back to the inbound number.Static class file
Finally we'll create the static class file.
- Navigate to your project's top level.
- Create a file called
Globals.cs
. - Copy the following code and paste its contents into
Globals.cs
:
using Sinch.SMS.Groups;
public static class Globals
{
public static Group? SmsGroup { get; set; }
}
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 created in Program.cs
and make it available to InboundController
. As mentioned above, this is only necessary because this tutorial creates the group as part of the application setup. If you already have a preexisting group, you won't need this class.