IVR: Screening & Recording with C# and ASP.NET MVC

Download the Code

ET Phone Home 

This ASP.NET MVC sample application is modeled after a typical call center experience, but with more Reese's Pieces.

Stranded aliens can call an agent and receive instructions on how to get off of Earth safely. In this tutorial, we'll show you the key bits of code that allow an agent to send a caller to voicemail, and later read transcripts and listen to voicemails.

To run this sample app yourself, download the code and follow the instructions on GitHub.

Read how Hulu built an IVR on Twilio that lets customers waiting on hold schedule a call back.

Route the call to an agent

When our alien caller chooses a planet, we need to figure out where to route the call. Depending on their input we will route this call to a given extension. Extensions are used to look up an agent. Any string can be used to define an extension.

Once we look up the agent, we can use the <Dial> verb to dial the agent's phone number and try to connect the call.

Loading Code Samples...
Language
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
IVRRecording.Web/Controllers/ExtensionController.cs
Route the call to an agent

IVRRecording.Web/Controllers/ExtensionController.cs

With this information, we present aliens with a list of available agents so they can pick one. Let's see how we look up an agent.

Look up an agent

When we receive a call from an alien we give them a set of options. In this case, the options are:

  • For Brodo, press 1
  • For Dagobah, press 2
  • For Oober, press 3

When our alien caller has made their choice we use the key-press to look up an Agent.

Loading Code Samples...
Language
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
IVRRecording.Web/Controllers/ExtensionController.cs
Find an agent by extension

IVRRecording.Web/Controllers/ExtensionController.cs

Now that our user has chosen their agent, our next step is to connect the call to that agent.

Call the agent

This code begins the process of transferring the call to our agent.

By passing a url to the <Number> noun, we are telling Twilio to make a POST request to the Agent/ScreenCall route after the agent has picked up but before connecting the two parties.

Essentially we are telling Twilio to execute some TwiML that only the agent will hear.

Loading Code Samples...
Language
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
IVRRecording.Web/Controllers/ExtensionController.cs
Connect the call to an Agent

IVRRecording.Web/Controllers/ExtensionController.cs

Our agent can now be called, but how does our agent interact with this feature? Let's dig into what is happening in the agent's screening call.

The agent screens the call

When our agent picks up the phone, we use a <Gather> verb to ask them if they want to accept the call.

If the agent responds by entering any digit, the response will be processed by our Agent/ConnectMessage route. This will <Say> a quick message and continue with the original <Dial> command to connect the two parties.

Loading Code Samples...
Language
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
IVRRecording.Web/Controllers/AgentController.cs
Handle the ScreenCall and ConnectMessage events

IVRRecording.Web/Controllers/AgentController.cs

Now our agent can interact with the call, but what if our agent is currently out? In these cases it's helpful to have voicemail set up.

Send the caller to voicemail

When Twilio makes a request to our Call action method, it will pass a DialCallStatus argument to tell us the call status. If the status was "completed", we hang up. Otherwise, we need to <Say> a quick prompt and then <Record> a voicemail from the alien caller.

We also specify an action for <Record>. This route will be called after the call and recording have finished. The route will say "Goodbye" and then <Hangup>.

Loading Code Samples...
Language
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
IVRRecording.Web/Controllers/AgentController.cs
Redirect a call to voicemail and end the call

IVRRecording.Web/Controllers/AgentController.cs

Now let's take a step back to see how to actually record the call.

Record the caller

When we tell Twilio to record, we have a few options we can pass to the <Record> verb.

Here we instruct <Record> to stop the recording at 20 seconds, to transcribe the call, and to send the transcription to the agent when it's complete.

Notice that we redirect to a URL that is specific to this agent. This is a convenient way to specify which agent was called to produce the voice message. This way we can also save the associated agent together with the voicemail.

Loading Code Samples...
Language
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
IVRRecording.Web/Controllers/AgentController.cs
Record a call

IVRRecording.Web/Controllers/AgentController.cs

Finally, we will see how to view an agent's voicemail.

View an agent's voicemail

Once we look up the agent, all we need to do is display their recordings. We bind the agent, along with their recordings, to a View.

It is possible to look up recordings via the Twilio REST API, but since we have all of the data we need in the transcribeCallback request, we can easily store it ourselves and save a roundtrip.

Loading Code Samples...
Language
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
IVRRecording.Web/Controllers/AgentController.cs
Handle the agent's index page

IVRRecording.Web/Controllers/AgentController.cs

That's it! We've just implemented an IVR with real Agents, call screening and voicemail.

Where to next?

 If you're a C# developer working with Twilio, you might want to check out these other tutorials.

Part 1 of this Tutorial: ET Phone Home Service - IVR Phone Trees

Increase your rate of response by automating the workflows that are key to your business.

Appointment Reminders

Send your customers a text message when they have an upcoming appointment - this tutorial shows you how to do it from a background job.

Did this help?

Thanks for checking out this tutorial! If you have any feedback to share with us, we'd love to hear it. Connect with us on Twitter and let us know what you build!

Agustin Camino
Kat King
Hector Ortega
Andrew Baker

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
using System.Collections.Generic;
using System.Web.Mvc;
using IVRRecording.Web.Models;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

namespace IVRRecording.Web.Controllers
{
    public class ExtensionController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public ExtensionController() : this(new AgentRepository()) {}

        public ExtensionController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // POST: Extension/Connect
        [HttpPost]
        public TwiMLResult Connect(string digits)
        {
            var extension = digits;
            var agent = FindAgentByExtension(extension);
            if (agent == null)
            {
                return RedirectToMenu();
            }

            var response = new VoiceResponse();

            response.Say("You'll be connected shortly to your planet.",
                voice: "alice", language: "en-GB" );

            var dial = new Dial(action: Url.Action("Call", "Agent", new { agentId = agent.Id }));
            dial.Number(agent.PhoneNumber, url: Url.Action("ScreenCall", "Agent"));
            response.Dial(dial);

            return TwiML(response);
        }

        private Agent FindAgentByExtension(string extension)
        {
            var planetExtensions = new Dictionary<string, string>
            {
                {"2", "Brodo"},
                {"3", "Dagobah"},
                {"4", "Oober"}
            };

            string agentExtension;
            planetExtensions.TryGetValue(extension, out agentExtension);
            return _repository.FindByExtension(agentExtension);
        }

        private TwiMLResult RedirectToMenu()
        {
            var response = new VoiceResponse();
            response.Redirect(Url.Action("Welcome", "IVR"));

            return TwiML(response);
        }
    }
}
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}
using System;
using System.Web.Mvc;
using IVRRecording.Web.Models.Repository;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;
using System.Xml.Linq;

namespace IVRRecording.Web.Controllers
{
    public class AgentController : TwilioController
    {
        private readonly IAgentRepository _repository;

        public AgentController() : this(new AgentRepository()) {}

        public AgentController(IAgentRepository repository)
        {
            _repository = repository;
        }

        // GET: Agent
        public ActionResult Index()
        {
            var agents = _repository.All();
            return View(agents);
        }

        // POST: Agent/Call
        [HttpPost]
        public TwiMLResult Call(string agentId, string dialCallStatus)
        {
            if (dialCallStatus == "completed")
            {
                var emptyResponse = new XDocument(new XElement("Root", ""));
                return new TwiMLResult(emptyResponse);
            }

            var response = new VoiceResponse();
            response.Say(
                body: "It appears that no agent is available. " +
                         "Please leave a message after the beep",
                language: "en-GB",
                voice: "alice"
            );

            response.Record(
                maxLength: 20,
                playBeep: true,
                action: Url.Action("Hangup"),
                transcribeCallback: Url.Action("Create", "Recording", new {agentId})
            );

            response.Say(
                body: "No record received. Goodbye",
                language: "en-GB",
                voice: "alice"
            );

            response.Hangup();

            return TwiML(response);
        }

        // POST: Agent/ScreenCall
        [HttpPost]
        public TwiMLResult ScreenCall(string from)
        {
            var response = new VoiceResponse();

            var incomingCallMessage = "You have an incoming call from: " +
                                      SpelledPhoneNumber(from);
            var gather = new Gather(
                numDigits: 1,
                action: Url.Action("ConnectMessage")
            );
            gather.Say(incomingCallMessage)
                  .Say("Press any key to accept");
            response.Gather(gather);

            response.Say("Sorry. Did not get your response");
            response.Hangup();

            return TwiML(response);
        }

        // GET: Agent/ConnectMessage
        public TwiMLResult ConnectMessage()
        {
            var response = new VoiceResponse()
                .Say("Connecting you to the extraterrestrial in distress");
            return TwiML(response);
        }

        // POST: Agent/Hangup
        [HttpPost]
        public TwiMLResult Hangup()
        {
            var response = new VoiceResponse();
            response.Say(
                body: "Thanks for your message. Goodbye",
                language: "en-GB",
                voice: "alice"
            );
            response.Hangup();

            return TwiML(response);
        }

        private static string SpelledPhoneNumber(string phoneNumber)
        {
           return string.Join(", ", phoneNumber.ToCharArray());
        }
    }
}