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 the Subscribe 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 the Globals.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 the Program.cs file. Open that file and replace its contents with the following code:
Copy
Copied
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.

Copy
Copied
using Sinch;

var sinch = new SinchClient("YOUR_project_id",
                            "YOUR_access_key", 
                            "YOUR_access_secret");
You can also implement the client using ASP.NET dependency injection. SinchClient is thread safe, so it's fine to add it as a singleton:
Copy
Copied
builder.Services.AddSingleton<ISinchClient>(x => new SinchClient(
    builder.Configuration["YOUR_project_id"],
    builder.Configuration["YOUR_access_key"],
    builder.Configuration["YOUR_access_secret"]));
Also, ensure that your 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 beneath var app = builder.Build();.
Copy
Copied
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 the InboundController.cs file. This is the centerpeice of our application and contains the auto subscribe method. To add this file:
  1. Navigate into the Controllers folder.
  2. Create a file called InboundController.cs.
  3. 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:

Copy
Copied
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:
Copy
Copied
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:
Copy
Copied
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 variable autoReply.
  • 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 variable autoReply.
  • 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:
Copy
Copied
var response = await _sinchClient.Sms.Batches.Send(new SendTextBatchRequest
{
    Body = autoReply,
    DeliveryReport = Sinch.SMS.DeliveryReport.None,
    To = new List<string>() { fromNumber },
    From = toNumber
});
When the 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.

  1. Navigate to your project's top level.
  2. Create a file called Globals.cs.
  3. Copy the following code and paste its contents into Globals.cs:
Copy
Copied
using Sinch.SMS.Groups;
public static class Globals
{
    public static Group? SmsGroup { 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 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.
We'd love to hear from you!
Rate this content:
Still have a question?
 
Ask the community.