Swimburger

Use XML Literals in Visual Basic .NET to generate TwiML

Niels Swimberghe

Niels Swimberghe - - .NET

Follow me on Twitter, buy me a coffee

Use XML Literals in Visual Basic .NET to generate TwiML

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

While JSON and YAML have become very popular data serialization languages, XML is still everywhere. XML is used on the HTML page you are reading right now. XML is used in your .NET project files and MSBuild scripts. Twilio also has their own flavor of XML called TwiML, but more on that later.

If you need to work with XML and are a Visual Basic .NET (VB) developer, then you're in luck because VB has a built-in feature for generating XML called XML Literals. In this tutorial, you'll learn how to generate TwiML with XML Literals with an ASP.NET Core Minimal API.

Prerequisites #

Here's what you will need to follow along:

You can find the source code for this tutorial on GitHub. Use it if you run into any issues, or submit an issue, if you run into problems.

Before creating your application, let's get you up to speed on how Twilio uses webhooks and TwiML to respond to text messages and voice calls.

Webhooks and TwiML #

Using Twilio, you can build programmatic text message and voice call applications. Twilio can do a lot of things like playing audio, gathering input, and recording a call, but Twilio doesn't know what you want to do in response to voice calls and text messages. That's why when Twilio receives a call or text message, Twilio will send an HTTP request to your application asking for instructions.

A webhook is a user-defined HTTP callback. When an event happens in a service, your application is notified of that event using an HTTP request.

Twilio uses webhooks heavily throughout all its products. Here's a diagram of what it looks like when there's an incoming text message to your Twilio Phone Number and your application is handling the messaging webhook:

Phone texts "Ahoy!" to a Twilio Phone Number, Twilio sends the SMS details (from and to phone number and the body of the message) via HTTP to your web application, then your application responds with TwiML instructions instructing to respond with "Hi!". Twilio receives the instructions and sends "Hi!" back to the original sender.

When your Twilio Phone Number receives a text message, Twilio will send an HTTP request with the message's details to your application. Your application then has to respond with TwiML (Twilio Markup Language) to instruct Twilio how to respond.

TwiML is XML with special tags defined by Twilio to provide instructions on how to respond to messages and voice calls. In the diagram depicted above, Twilio will respond with "Hi!" because the app responded with the following TwiML:

<?xml version="1.0" encoding="utf-8"?>
<Response>
  <Message>Hi!</Message>
</Response>

You can learn more about TwiML for Programmable Messaging here and TwiML for Programmable Voice here.

Now that you know what webhooks and TwiML are, let's create a voice call application with ASP.NET Core.

Create an ASP.NET Core Minimal API in Visual Basic .NET #

Unlike C# and F#, there is no Minimal API template for VB to quickly create a Minimal API project.That doesn't mean you can't create Minimal APIs with VB, but you do have to do it yourself.

You can follow this guide on creating a Minimal API using VB, or you can start from this GitHub branch using the Git CLI or by downloading the ZIP file.

I named my project TwimlXmlLiterals, but if you followed the guide on creating a Minimal API, it'll be MinimalApiVb instead. Name your project however you want and, in the terminal, navigate to your project folder

cd TwimlXmlLiterals

In that folder, you'll find a file named Program.vb file that looks like this:

Imports System
Imports Microsoft.AspNetCore.Builder

Module Program
    Sub Main(args As String())
        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()
        app.MapGet("/", Function() "Hello World!")

        app.Run()
    End Sub
End Module

The HTTP GET endpoint at the root "/" responds with the text "Hello World!".

Run the following command to start the project:

dotnet run

The command will print the URL where your app is running. Open the URL in your browser and verify "Hello World!" is being returned. Great, your Minimal API is working!

Now, stop the application by switching back to your terminal and pressing ctrl + c.

Use XML Literals to generate TwiML #

Since TwiML is a subset of XML, you can use VB's XML Literals to generate TwiML.

Update the Program.vb file to match the following code:

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http

Module Program
    Sub Main(args As String())
        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.MapGet("/what-does-the-fox-say", Function() Results.Text(
            <Response>
                <Gather action="/answer" method="GET" input="speech">
                    <Say>What does the fox say?</Say>
                </Gather>
                <Say>Ring-ding-ding-ding-dingeringeding!</Say>
            </Response>.ToString(),
            "application/xml"
            ))

        app.MapGet("/answer", Function(speechResult As String) Results.Text(
            <Response>
                <Say>You said: <%= speechResult %></Say>
            </Response>.ToString(),
            "application/xml"
            ))

        app.Run()
    End Sub
End Module

When your Twilio Phone Number receives a call, Twilio will send an HTTP GET request to the /what-does-the-fox-say endpoint, which will set the content-type response header to application/xml, and return the following TwiML in the response:

<Response>
  <Gather action="/answer" method="GET" input="speech">
    <Say>What does the fox say?</Say>
  </Gather>
  <Say>Ring-ding-ding-ding-dingeringeding!</Say>
</Response>

When Twilio receives the above TwiML, it'll ask the caller "What does the fox say?" and listen for a speech response. When the caller responds, Twilio will send an HTTP request, this time to the /answer endpoint, with the transcription of what the caller said. If the caller doesn't respond, Twilio will say "Ring-ding-ding-ding-dingeringeding!" to the caller.

The /answer endpoint will retrieve the transcription from the query string parameter SpeechResult by binding it to the speechResult parameter. SpeechResult is used to construct some more TwiML. The /answer endpoint will generate the following TwiML when the caller says "ring ding ding":

<Response>
    <Say>You said: ring ding ding</Say>
</Response>

When Twilio receives this TwiML, Twilio will convert "You said: ring ding ding" to speech and stream the audio to the caller.

In case you're not familiar with the song I am referencing in this app, "What does the fox say?" originates from this famous song.

Start your .NET application using your editor, or using the terminal using the .NET CLI:

dotnet run

Make the application publicly accessible #

Before integrating Twilio, open a browser and navigate to your web application URL with the suffix /what-does-the-fox-say to verify the TwiML that is generated.

For Twilio to be able to send HTTP requests to your local web server, the server needs to become publicly accessible. ngrok is a free secure tunneling service that can make your local web servers public.

To start ngrok, run the following ngrok command in a separate terminal:

ngrok http [YOUR_ASPNET_URL]

Then, replace [YOUR_ASPNET_URL] with the localhost URL from your .NET application. If you're using an HTTPS localhost URL, you'll need to authenticate ngrok. The ngrok command will display an HTTPS Forwarding URL that makes your local web server public.

ngrok http command output showing information about the secure tunnel, most importantly the public forwarding URLs

Configure your Twilio Phone Number #

Now it's time to update your Twilio Phone Number to send HTTP requests to your /what-does-the-fox-say endpoint via the ngrok Forwarding URL. The URL should look something like https://cd2f8809cbd0.ngrok.io/what-does-the-fox-say.

Go to the Active Phone Numbers section in the Twilio Console and click on your Twilio Phone Number.
This will take you to the configuration form for the phone number. Find the Voice & Fax section and under the "A CALL COMES IN" label, set the dropdown to "Webhook". In the text field next to it, enter your ngrok forwarding URL with /what-does-the-fox-say appended to it, and select “HTTP GET” in the last dropdown. Finally, click the Save button at the bottom of the page.

Voice & Fax section in the Twilio Phone Number configuration page. Under the "A CALL COMES IN" label, a dropdown is set to "Webhook", the text field next to it is configured with "https://cd2f8809cbd0.ngrok.io/what-does-the-fox-say", and the dropdown next to that is set to "HTTP GET".

Test that the application works #

To test out your application, call your Twilio Phone Number. You should hear the question "What does the fox say?" which you can respond to, wait 5 seconds, and then your response will be read back to you.

After you've done that, stop your .NET application using your editor, or if you're using the terminal, press ctrl + c.

Other ways to generate TwiML #

There are many other ways you could generate TwiML. Since TwiML is XML, you can use the APIs from the System.Xml and System.Xml.Linq namespace. Twilio also has a helper library for .NET that lets you generate TwiML in an object-oriented way, and the helper library for ASP.NET helps you return the TwiML in the HTTP response.

In the terminal where you ran your project, run the following commands to add the Twilio package and Twilio.AspNet.Core package:

dotnet add package Twilio
dotnet add package Twilio.AspNet.Core

Then, update the Program.cs file to match the following code:

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http
Imports Twilio.AspNet.Core.MinimalApi
Imports Twilio.TwiML
Imports Twilio.TwiML.Voice

Module Program
    Sub Main(args As String())
        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.MapGet("/what-does-the-fox-say", Function()
            Dim response = new VoiceResponse
            Dim gather = new Gather(
                input := New List(Of Gather.InputEnum) From {Voice.Gather.InputEnum.Speech},
                action := new Uri("/answer", UriKind.Absolute),
                method := Twilio.Http.HttpMethod.Get
                )
            gather.Say("What does the fox say?")
            response.Append(gather)
            response.Say("Ring-ding-ding-ding-dingeringeding!")
            Return Results.Extensions.TwiML(response)
        End Function)

        app.MapGet("/answer", Function(speechResult As String) 
            Dim response = new VoiceResponse
            response.Say($"You said: {speechResult}")
            Return Results.Extensions.TwiML(response)
        End Function)
        
        app.Run()
    End Sub
End Module

The resulting TwiML will be the same as before. Under the hood, the helper library uses the APIs from System.Linq.Xml to generate the XML string.

Now, you may be wondering, why would you use XML Literals when you can use the Twilio helper library, or maybe you're wondering why you would use the helper library when you can use XML Literals.

The advantages of creating TwiML using XML Literals, is that you don't need any dependencies and it's more memory efficient & performant. However, it is easier to make a mistake in your TwiML and there will be no compilation errors to prevent you from doing that.

The advantages of using the Twilio helper library are that you are using fully typed objects and methods that provide IntelliSense in IDEs. If you make a typo, your project will not build and you will receive a compiler error telling you where your typo is. However, you do depend on the Twilio helper library and its dependencies, and you have to create a bunch of objects that are ultimately serialized to an XML string which is less memory efficient and slower.

They both have their own advantages and disadvantages, but you can mix and match based on your use case.

Next steps #

You learned how Twilio uses webhooks and TwiML to give you control over how to respond to a call or text message. You then learned how to generate TwiML instructions using VB's XML Literals, and compared it to generating TwiML with the Twilio helper library.

Here are a couple more resources to further your learning on Minimal APIs and Twilio:

We can't wait to see what you build. Let us know!

Related Posts

Related Posts