How To Build a Voicemail with ASP.NET Core and NancyFX
Published on April 28, 2021

Have you ever wondered if Meg Ryan would rather listen to Tom Hanks voice instead of simply reading messages?

In my opinion, "Call me Maybe" sounds more exciting than "You've got mail".

So if like me, you'd like to provide someone - your customers perhaps - with a phone number where they can leave you a message, you create your own voicemail powered by Nexmo Voice APIs.

Learning Objectives

In this tutorial, we will:

  • Create an ASP.NET Core app.

  • Use NancyFX with ASP.NET Core.

  • Create a Nexmo voice application.

  • Create and return NCCOs.

  • Run and test the code using Ngrok.

Prerequisites

  • Visual Studio 2017 or higher.

  • A project setup for this tutorial, which you can find on Github.

  • Optional: The Nexmo CLI. <sign-up></sign-up>

Configuration

To use The Nexmo Voice API, we need to create a voice application.

The configuration steps are detailed in the Nexmo Voice API with ASP.NET: Before you start post.

Once the configuration is done successfully, we are ready to create a voicemail.

Creating a Voicemail

Similar to the previous blog posts in this series, we are going to use NancyFX along side our ASP.NET Core project.

First of all, we need to add Nancy to our project:

PM> Install-Package Nancy
PM> Install-Package Microsoft.AspNetCore.Owin

To allow Nancy to handle any HTTP requests, we need to tell ASP.NET Core to use Nancy via Owin in the Configure method of Startup.cs.

using Microsoft.AspNetCore.Builder;
using Nancy.Owin;

namespace NexmoVoiceASPNetCoreQuickStarts
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseOwin(x => x.UseNancy());
        }
    }
}

The next step is to create a Nancy module in which we setup a route to /webhook/answer which will respond with the ncco returned by GetVoiceMailNCCO(). For more details on exactly how to write an ncco check out the NCCO reference in our documentation.

using Nancy;
using Newtonsoft.Json.Linq;

namespace NexmoVoiceASPNetCoreQuickStarts
{
    public class VoiceModule : NancyModule
    {
        public VoiceModule()
        {
            Get["/webhook/answer/"] = x => { var response = (Response)GetVoiceMailNCCO();
                                             response.ContentType = "application/json";
                                             return response;
                                           };
        }

        private string GetVoiceMailNCCO()
        {
            dynamic TalkNCCO = new JObject();
            TalkNCCO.action = "talk";
            TalkNCCO.text = "Hello. You have reached Bibi. Please, leave your message after the beep.";
            TalkNCCO.voiceName = "Emma";

            dynamic RecordNCCO = new JObject();
            RecordNCCO.action = "record";
            RecordNCCO.beepStart = true;
            RecordNCCO.eventUrl = "https://example.com/recording";
            RecordNCCO.endOnSilence = 3;


            JArray nccoObj = new JArray
            {
                TalkNCCO,
                RecordNCCO
            };

            return nccoObj.ToString();
        }
    }
}

The above code will greet the caller and instruct them when to begin their message.

Once the message is recorded, Nexmo will make a request to the URL in the 'record' action which is 'https://example.com/recording' currently.

Let us fix that by sending the information about the recording to another route /webhook/voicemail

public VoiceMailModule()
        {
            Get["/webhook/answer/"] = x => { var response = (Response)GetVoiceMailNCCO();
                                             response.ContentType = "application/json";
                                             return response;
                                           };
            Post["/webhook/voicemail/"] = x => { var response = (Response)GetRecording(Request.Query["recording_url"]);
                                                 response.ContentType = "application/json";
                                                 return response;
                                               };
            Post["/webhook/event"] = x => Request.Query["status"];
        }

private Response GetRecording(string url)
        {
            var client = new Client(creds: new Nexmo.Api.Request.Credentials
            {
                ApiKey = "NEXMO_API_KEY",
                ApiSecret = "NEXMO_API_SECRET",
                ApplicationId = "NEXMO_APPLICATION_ID",
                ApplicationKey = "NEXMO_APPLICATION_PRIVATE_KEY"
            });

            var result = client.getRecording(url);
            string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            string localFilename = "downloaded.mp3";
            string localPath = Path.Combine(documentsPath, localFilename);
            File.WriteAllBytes(localPath, result);
        }

Some more configuration steps are still required to be able to test the code.

If you've been following along so far, you've already configured your Nexmo account and created a voice app as shown in this post. We need to link this app to a the Nexmo phone number that we are going to call. If you don't have a number, you can purchase one using the dashboard or the CLI:

nexmo number:buy --country_code US

Similarly to link the number, you can use the dashboard or the CLI:

nexmo link:app NEXMO_PHONE_NUMBER NEXMO_APP_ID

We need to tell Nexmo which URL to make a request to when a call is received - this is called the answer_url. For me, this url is http://localhost:63286/webhook/answer and that's only running locally.

To expose our webhook answer url, we will use Ngrok.

ngrok http 63286

We now have a new url (mine is http://<SUBDOMAIN>.ngrok.io) that can be used as the answer_url for the voice application.

Update your application with your new answer_url. It should look like http://[id].ngrok.io/webhook/answer Now, you can run the app.

Learn More

API References and Tools

Nexmo Getting Started Guides for ASP.NET

Rabeb OthmaniVonage Alumni

Rabeb was a Developer Advocate at Nexmo focusing on cloud communication APIs and helping developers get the best experience possible when building their apps. Other than writing code for a living, Rabeb advocates for bringing more women and minorities into tech, thus her involvement with Women Who Code and different tech communities. She leads the Women Who Code Network in Bristol.

Ready to start building?

Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls-all at your fingertips.