Swimburger

What's new in the Twilio helper library for ASP.NET (v5.73.0 - April 2022)

Niels Swimberghe

Niels Swimberghe - - .NET

Follow me on Twitter, buy me a coffee

What's new in the Twilio helper library for ASP.NET (v5.73.0 - March 2022)

This blog post was written for Twilio and originally published at the Twilio blog.

The Twilio helper library for ASP.NET (Twilio.AspNet) is a community-driven open-source project to make integrating Twilio with ASP.NET easier, for both ASP.NET Core and ASP.NET MVC on .NET Framework. The library helps you with very common use cases like:

  • Responding to Twilio webhook requests with TwiML objects from the official Twilio SDK for C# and .NET.
  • Binding data from Twilio webhook requests to strongly typed .NET objects.
  • Validating webhook requests originate from Twilio and rejecting them if not.

As .NET and ASP.NET is evolving, the Twilio.AspNet contributors are enhancing the library to take advantage of the newest capabilities and best practices. So what's new?

What's old in Twilio.AspNet #

Actually, before I share the shiny new additions, let me share what is already part of the library. After all, this is the first blog post to share news about the library.

Handle Twilio webhook requests with ASP.NET #

In previous versions of Twilio.AspNet, you could create a controller to respond to Twilio webhooks like this:

using Twilio.AspNet.Common;
using Twilio.AspNet.Core; // or .Mvc for .NET Framework
using Twilio.TwiML;

public class SmsController : TwilioController
{
    public TwiMLResult Index(SmsRequest request)
    {
        var response = new MessagingResponse();
        response.Message($"Ahoy {request.From}!");
        return TwiML(response);
    }
}

If you're using the routing convention that comes out-of-the-box with MVC, this action can be reached via the path /Sms/Index or /Sms (Index is the default). When you configure the URL with this path as your Twilio messaging webhook, the Index action will start receiving the messages sent to your Twilio Phone Number. When a webhook request comes in:

  • The HTTP request data will be bound to the SmsRequest parameter. This way you can conveniently inspect the data using a strongly typed .NET object. The SmsRequest class is provided by the Twilio.AspNet library.
  • The code will then create a new MessagingResponse which is a TwiML class from the official Twilio SDK for C# and .NET. response.Message will create TwiML instructions to respond with a message that looks like "Ahoy +11234567890!".
  • The TwiML method accepts the TwiML object and creates a TwiMLResult which will write the TwiML to the HTTP response. This TwiML method is inherited from the TwilioController class provided by the Twilio.AspNet library.

As a result, when someone texts your Twilio Phone Number, Twilio will send a text message back saying "Ahoy +11234567890!".

Similarly, you can also respond to voice calls as shown in this sample:

using Twilio.AspNet.Common;
using Twilio.AspNet.Core; // or .Mvc for .NET Framework
using Twilio.TwiML;

public class VoiceController : TwilioController
{
    public TwiMLResult Index(VoiceRequest request)
    {
        var response = new VoiceResponse();
        response.Say($"Ahoy! Are you from {request.FromCity}?");
        return TwiML(response);
    }
}

After configuring the voice webhook, when the phone number receives a phone call, Twilio will send an HTTP request to the Index action. The data from the HTTP request will be bound to the VoiceRequest parameter. This data is then used to construct TwiML instructions. For example, when I call the phone number, it would transcribe the message to audio and say "Ahoy! Are you from BELTSVILLE?".

Secure your Twilio webhook #

Webhooks by its very nature have to be publicly accessible to the internet, otherwise Twilio can't send HTTP requests to them. As a result, everyone else can also send HTTP requests to your webhook. To make sure HTTP requests originate from Twilio and not some bad actor, you can add the ValidateRequest attribute to your controllers or actions. This attribute will verify the signature of the HTTP request to ensure the request originated from Twilio.

What's new in Twilio.AspNet #

In recent months, a couple of new versions of the Twilio.AspNet library have been released with the latest being version 5.73.0. Here's an overview of the changes:

  • 🎉 NEW FEATURES  
    • Support for Minimal API in ASP.NET Core (PR #35)
    • TwiML extension methods for controllers so you don't have to inherit from TwilioController (PR #45)

You can find more information about these new features later in the article.

  • 🙌 ENHANCEMENTS
    • The project files and build scripts have been updated. (PR #52)
      • The .NET Framework based project files have been updated to use the new SDK-style project files. Now you can use the same .NET CLI commands to build and test the .NET Framework projects as you can with the .NET (Core) projects. As a result, it's easier to build, test, and pack the projects for this library.
      • With the increased consistency, the build scripts have also been updated and no longer rely on the nuget and xunit executables that were previously embedded in the repository.
    • The README.md file has been updated to refresh outdated information and include more samples on how to use the library. (PR #48, PR #50)
    • A new CHANGELOG.md file has been created so users can quickly learn about enhancements, bug fixes, and breaking changes whenever a new version is released. (PR #52)
    • The metadata of the NuGet packages has been updated to refresh outdated information. This metadata is shown in places like NuGet.org, the NuGet Package Manager for Visual Studio, and the NuGet window for JetBrains Rider (PR #52)
  • 🪳 BUG FIXES
    • A bug was fixed where Swagger would complain about the TwiML methods when inheriting from the TwilioController. (PR #43)

TwiML for Minimal API #

ASP.NET Core 6 introduced a new way to write web APIs that sparks joy, and now Twilio.AspNet.Core has support to return TwiML in Minimal APIs just like you could before with controllers.

Here's an example with C#:

using Microsoft.AspNetCore.Mvc;
using Twilio.AspNet.Core.MinimalApi;
using Twilio.TwiML;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/sms", ([FromQuery] string from) =>
{
    var response = new MessagingResponse();
    response.Message($"Ahoy {from}!");
    return Results.Extensions.TwiML(response);
});

app.MapPost("/sms", async (HttpRequest request) =>
{
    var form = await request.ReadFormAsync();
    var from = form["from"];
    response.Message($"Ahoy {from}!");
    return Results.Extensions.TwiML(response);
});

app.Run();

When Twilio sends an HTTP POST or GET request to your /sms webhook, it will be handled by one of the two endpoints defined above. Both endpoints do exactly the same as the prior MVC controller example.

Unfortunately, Minimal APIs do not support the same data binding from HTTP request data to parameters that MVC does. For HTTP GET requests, you have to bind individual query string parameters using the [FromQuery] attributes to .NET parameters with simple data types like strings, integers, floats, doubles, etc.
For HTTP POST requests, you have to accept the HttpRequest as a parameter and manually retrieve the desired parameters from the Form property.

Lastly, the TwiMLResponse is passed to the Results.Extensions.TwiML method which will create a TwiMLResult that will take care of writing the TwiML to the HTTP response body. The Results.Extensions.TwiML is an extension method that you can import by using the Twilio.AspNet.Core.MinimalApi namespace.

For voice calls, you can use a VoiceResponse instead of a MessagingResponse, everything else works the same.

TwiML extension methods for controllers #

As shown in the first sample in this article, you can let your controller inherit from TwilioController which gives you access to the TwiML methods. These TwiML methods create a TwiMLResult object which takes care of writing the TwiML to the HTTP response body. However, if your controller already inherits from another base class, you can't also inherit from TwilioController. It's one or the other. That's why Twilio.AspNet (.Core and .Mvc) now has the same methods as extension methods. You can now use this.TwiML to return TwiML objects in controllers. Here's the same MVC example using the TwiML extension methods instead of the methods from the TwilioController.

using Twilio.AspNet.Common;
using Twilio.AspNet.Core; // or .Mvc for .NET Framework
using Twilio.TwiML;

public class SmsController : Controller
{
    public TwiMLResult Index(SmsRequest request)
    {
        var response = new MessagingResponse();
        response.Message($"Ahoy {request.From}!");
        return this.TwiML(response);
    }
}

You can also use a VoiceResponse instead of a MessagingResponse to return TwiML for Voice webhooks.

Go use the shiny new bits #

You can take advantage of these new features and enhancements by installing the latest version of the Twilio helper library for ASP.NET. You can find the installation instructions in the readme of the Twilio.AspNet GitHub repository. If you like this library, consider giving us a star on the GitHub repo and submit an issue if you run into problems.

We can't wait to see what you'll build with Twilio.AspNet. Let us know on social media and don't forget to @TwilioDevs and @RealSwimburger on Twitter or LinkedIn.