In this article, we are going to cover how to send an SMS with ASP.NET Core. To accomplish this, we are going to use Twilio as our SMS service to send an SMS message and automate a response when an SMS message is received.

To download the source code for this article, you can visit our Send an SMS with ASP.NET Core repository

This post is divided into the following parts:

Let’s dive in.

Setting up a Twilio SMS Account

The first thing we need to do is create a Twilio account. When we create an account, we are going to be given a free trial account with a 15.50 USD. We can use the trial balance toward purchasing a phone number and sending and receiving messages.

See the Dashboard:

Twilio Dashboard - ASP.NET Core

Now that we have an account let’s make a note of our account SID and auth token. Let’s move on and get a Twilio number for our project. Let’s click on “Get a Trial Number” :

Twilio Number - SMS and ASP.NET Core

Twilio is going to assign us a number or we can search for a different one. We are going to stick with the one provided by Twilio.

Configuring an ASP.NET Core Project with Twilio

Now that we have a Twilio account set up, let’s create a new ASP.NET Core Web API project:

dotnet new webapi --no-https -o SmsProject

The first thing we are going to do is install the Twilio NuGet Edit SmsProject.csproj to install the NuGet Package:

dotnet add package Twilio

After installing the Twilio package, we are going to modify appsettings.json with the account SID and the auth token found on the Twilio dashboard:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "Twilio": {
    "AccountSid": "placeholder",
    "AuthToken": "placeholder"
  }
}

Customizing the Twilio Client

Let’s move on to the Twilio client. This is the piece of code that will implement the Twilio API and make it reusable across the project. Let’s create a folder called Services and create the TwilioClient class:

using TwilioClient SystemHttpClient = System.Net.Http.HttpClient;
public class TwilioClient : ITwilioRestClient
{
    private readonly ITwilioRestClient _innerClient;

    public TwilioClient(IConfiguration config, SystemHttpClient httpClient)
    {
        // customize the underlying HttpClient
        httpClient.DefaultRequestHeaders.Add("X-Custom-Header", "CustomTwilioRestClient-Demo");

        _innerClient = new TwilioRestClient(
            config["Twilio:AccountSid"],
            config["Twilio:AuthToken"],
            httpClient: new SystemNetHttpClient(httpClient));
    }

    public Response Request(Request request) => _innerClient.Request(request);
    public Task<Response> RequestAsync(Request request) => _innerClient.RequestAsync(request);
    public string AccountSid => _innerClient.AccountSid;
    public string Region => _innerClient.Region;
    public Twilio.Http.HttpClient HttpClient => _innerClient.HttpClient;
}

By implementing the ITwilioRestClient from the Twilio package, we are able to customize the headers and make other changes before we use it to make requests. In the constructor, we are going to add a custom header and initialize the client object with the account SID and the auth token that we stored in appsettings.json. Check out our article on the Options Pattern for a better way of accessing data in appsettings.json.

The remainder of the class is simply methods and properties that return the corresponding properties from the private variable _client.

Now that we finished our client, let’s register it in Startup.cs so we can use it via dependency injection. Let’s modify the ConfigureServices methods within the Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddHttpClient<ITwilioRestClient, TwilioClient>();
}

Our project has been successfully configured with Twilio!

Sending an SMS

The next part of this project is to create an API that will allow us to send a text message to a phone number. First, we are going to need to define the SmsMessage model within a Models folder:

public class SmsMessage
{
    public string To { get; set; }
    public string From { get; set; }
    public string Message { get; set; }
}

The next part of our application is the API controller that will receive our requests. Let’s create the SmsController class within a Controllers folder:

[ApiController]
[Route("[controller]")]
public class SmsController : ControllerBase
{
    private readonly ITwilioRestClient _client;
    public SmsController(ITwilioRestClient client)
    {
        _client = client;
    }

    [HttpGet]
    public IActionResult SendSms(SmsMessage model)
    {
        var message = MessageResource.Create(
            to: new PhoneNumber(model.To),
            from: new PhoneNumber(model.From),
            body: model.Message,
            client: _client); // pass in the custom client

        return Ok("Success");
    }
}

Our controller begins by implementing ControllerBase. Then we initialize the custom client we defined by using dependency injection. Within the SmsController, we define the SendSms action method. When a POST request is sent to http://localhost:5000/sms, the controller is going to call this method. Our method is going to bind the body in the request to the model variable of type SmsMessage. Using the model variable we are going to populate the arguments for the Create method within the MessageResource class. The Create method is how we create SMS messages and pass them on to the Twilio service that is responsible for sending SMS messages.

Finally, we are going to test our API with Postman:

Postman - SMS and ASP.NET Core

Here is the fruit of our labor:

Received Text from Twilio - SMS and ASP.NET Core

We are going to notice that Twilio has prefixed its own message before the message that we defined. This is going to happen as long as our account remains a trial account.

Receiving an SMS

Now, we can move to the part of our API that is going to be responsible for receiving SMS messages.

First, we are going to install another Twilio NuGet package:

dotnet add package Twilio.AspNet.Core

Let’s continue by modifying SmsController.cs:

[ApiController]
[Route("[controller]")]
public class SmsController : TwilioController
{
    private readonly ITwilioRestClient _client;
    public SmsController(ITwilioRestClient client)
    {
        _client = client;
    }

    [HttpGet]
    public IActionResult SendSms(SmsMessage model)
    {
        var message = MessageResource.Create(
            to: new PhoneNumber(model.To),
            from: new PhoneNumber(model.From),
            body: model.Message,
            client: _client); // pass in the custom client

        return Ok("Success");
    }

    [HttpPost]
    public TwiMLResult ReceiveSms([FromForm]SmsRequest incomingMessage)
    {
        var messagingResponse = new MessagingResponse();
        messagingResponse.Message("Thank you. Your message was received.");

        return TwiML(messagingResponse);
    }
}

To enable receiving capabilities in our API, we need to change BaseController to TwilioController. The TwilioController class lets us use the SmsRequest, TwiMLResult, and TwiML classes. We use these classes to define the ReceiveSms action. This action is called when the Twilio service makes a POST request to http://localhost:5000/sms. In other words, when an SMS message is sent to our number, the Twilio service reacts by making a POST request to this action. In Twilio’s documentation, this is known as a webhook.

The method expects an SmsRequest object which is the format that Twilio will generate the data in the request body. The incoming message data lets us parse the message or find out the details of the sender. For this article, we are just going to acknowledge that a message was received and reply with a simple thank you message. To do this, we must create a MessagingResponse object with the desired message and return a TwiML object containing that MessagingResponse object.

Now our application is ready to be tested!

Testing with Ngrok

To get our application to behave correctly, all we need to do is configure Twilio with our webhook. However, because we are testing it with a development environment, we are going to need a tool that exposes our local server to the internet. We are going to use Ngrok for this.

After signing up for a free account and installing Ngrok, we are going to run the executable with the port number of our application:

path/to/ngrok 5000

Ngrok can also be launched with Visual Studio or VS Code with an extension from the marketplace:

Ngrok Tunnel

Now we can use the public address provided by Ngrok to configure our Twilio service.

Let’s go back to the Twilio website and navigate to the Phone Numbers Console:

Twilio Active Numbers - SMS and ASP.NET Core

Then we can scroll down to the “Messaging” section of the page and configure our webhook with the Ngrok provided address:

Twilio Webhook Configuration - SMS and ASP.NET Core

Now we are ready to test our application!

Let’s send a reply to our Twilio number:

SMS Reply from a Twillio service

And that’s it! Our application is now ready to send and receive SMS messages!

Conclusion

We have successfully configured our .NET Core project to send and receive SMS messages. To accomplish this, we used Twilio as our messaging service. In this article, we also learned how to integrate Twilio’s C# SDK into our Web API and implement a customizable client. Furthermore, this application can be extended to handle SMS subscriptions and organize mass texting campaigns.