In this tutorial, we'll learn how to receive SMS Messages from the Vonage Messages API, and push them out to a browser in real-time. We will use ASP.NET Core MVC for our API server and web page, and we will be using SignalR to allow us to receive SMS messages in real-time.
Jump Right to the Code
If you want to just pull the code from this demo, it can all be found in GitHub.
Prerequisites
You'll need a Vonage API account
You'll need the latest version of the .NET Core 3.1 SDK
You'll need either Visual Studio 2019, Visual Studio for Mac, or Visual Studio Code, I will be using Visual Studio 2019 for this demo
Optional: I used Ngrok to test this demo
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.
Create the App
Open Visual Studio and click "Create a new project," select "ASP.NET Core Web Application" and click "Next." Give your application a name. I am going to be naming my application, "ReceiveSmsAspNetCoreMvc." Then click create. On the next page, select "Web Application (Model-View-Controller)" and click "Create."
Install Dependencies
Since we are using SignalR, there are two types of dependencies we need to add. First, we'll need to add our NuGet package dependencies; then, we'll need to add our client package dependencies.
NuGet Dependencies
We need to install two NuGet packages:
There are multiple ways to do this; I will just use the dotnet CLI. Navigate to the project directory for your project and just run:
Client Side Packages
Since we are dependant on the SignalR Client-Side library, we shall also need to add the SignalR Client-Side library.
In Visual Studio, right-click on your projects wwwrooot
go to Add > Client-Side Library
. That will bring up a little dialog to help you add the library. For this demo, I used the following.
Provider: unpkg
Library: @microsoft/signalr@latest
Choose Specific files: I only selected
Files/dist/browser/signalr.js
andFiles/dist/browser/signalr.min.js
Target Location: wwwroot/js/signalr
After completing the form, it will look something like:
After filling out this form, you can click install, and it will install the required files under wwwroot/js/signalr
Create an SMS Hub
The way SignalR works, client browsers connect to something called Hubs. Hubs push messages from the server to each of their clients over whatever available mechanism they have. Typically is a WebSocket but can be done via Server-Side-Events(SSE) or Long-Polling. We need to create a Hub in our server to connect our server to our browser clients.
Create a new folder under your project called Hubs
. Under that folder, create a new C# file SmsHub.cs
. This file doesn't need to do much. It will just declare a class extending the Hub class. The file should look like the following.
using Microsoft.AspNetCore.SignalR;
namespace ReceiveSmsAspNetCoreMvc.Hubs
{
public class SmsHub : Hub
{
}
}
Configure Middleware
Configure Services
We now need to go into our startup.cs
file, and add the SignalR endpoints to our middleware. Adding the middleware will allow the SMS hub route to stand up and allow us to use SignalR in our browser clients. Let's crack open startup.cs
and find our way to the ConfigureServices
method. Add the line services.AddSignalR();
to this method, that will add the SignalR middleware to our server. After finishing our ConfigureServices
method will look like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSignalR();
}
Configure
Stay in startup.cs
and find the Configure
method. This method will contain a call to app.UseEndpoints
, which takes a function as an argument, inside that function, we will map the SmsHub
to the path /smsHub
. After finishing the app.UseEndpoints
call will look like:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<smshub>("/smsHub");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
</smshub>
Build an SMS Controller
Now that we have the middleware sorted, we need to add the method that will receive the SMS from Vonage. We will use an empty MVC Controller to this end. Right-click on the Controllers folder and go to add -> Controller, select "MVC Controller - Empty" and click "Add" name this SmsController
and click "Add" again.
Inject our SmsHub's Context
The first thing we'll need to do in our SmsController
injects the HubContext
for the SmsHub
. Declare an IHubContext
property called HubContext
, and then declare a SmsController
constructor that takes an IHubContext
as an argument and assign this parameter to the HubContext
property. Through the magic of dependency injection, the controller receives the hub context at creation.
/// <summary>
/// Allows access to all browser clients subscribed through the /smsHub
/// </summary>
public IHubContext<smshub> HubContext { get; set; }
public SmsController(IHubContext<smshub> hub)
{
HubContext = hub;
}
</smshub></smshub>
Add an Inbound Sms Handler
Now that we have access to the Hub Context, we need to add an API route for the inbound SMS. This route will be the route that Vonage uses to send a webhook to our application. This method will take the request, parse an InboundSms object from it, and send an InboundSms
signal to all of the clients connected to the hub. This method will then push the MSISDN and the text of the message down to the user. For reference, the MSISDN is the number from which the message originated. Add the following to your SmsController
.
[HttpPost("webhooks/inbound-sms")]
public async Task<iactionresult> InboundSms()
{
using (var reader = new StreamReader(Request.Body))
{
var json = await reader.ReadToEndAsync();
var inbound = JsonConvert.DeserializeObject<inboundsms>(json);
await HubContext.Clients.All.SendAsync("InboundSms", inbound.Msisdn, inbound.Text);
}
return NoContent();
}
</inboundsms></iactionresult>
Build a Frontend
With that taken care of, we just need to add a frontend to our app. To this end, we'll just take over the Home View. Open /Vies/Home/Index.cshtml
and go ahead and remove the div that contains the welcome text, we won't need that.
Next, we'll just add a couple of script imports. We'll import ~/js/sms.js
(which we'll create in a moment) and ~/js/signalr/dist/browser/signalr.js
which is the client library we imported before. Just add these two tags, and we'll be good to go.
<a href="http://~/js/signalr/dist/browser/signalr.js">http://~/js/signalr/dist/browser/signalr.js</a>
<a href="http://~/js/sms.js">http://~/js/sms.js</a>
The last thing we need to do here is to add the table where we'll display messages. We'll just give it two columns, From Number
and Message
- those will correspond to the Msisdn
and the Text
from our inbound SMS messages.
<h1>Messages</h1>
<table class="table" id="messageList">
<thead>
<tr>
<th>From Number</th>
<th>Message</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Add the SignalR Event Handler
The last thing that we need to do is to add an event handler for our InboundSms
event. We'll do that in the sms.js
file that we just referenced. Go ahead and add an sms.js
file to the /wwwroot/js
directory. There are three things we need to do in this file.
Build the SignalR connection to the smsHub
Register an event handler for
InboundSms
that will add a new row to our list of messagesStart the SignalR connection.
We can do all three of these by adding the following to the sms.js
file.
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/smsHub").build();
connection.on("InboundSms", function (fromNumber, text) {
var rowHtml =
'' +
fromNumber +
'' +
text +
'';
$('#messageList tbody').append(rowHtml);
});
connection.start()
.then(function () {
console.log("connection started");
})
.catch(function (err) {
console.log("Error encountered: " + err);
})
Testing
From a development perspective, that's all we needed to do, so let's go ahead and get into testing. We're going to test this with Ngrok to test this demo. Ngrok allows us to build a publicly accessible tunnel to our app, which is useful when we need to expose publicly accessible HTTP endpoints to our apps. If you are going to be testing this with IIS Express like I am, you will want to check out our explainer on the subject as there are special considerations. What this boils down to is that we need to add a --host-header
option when we start up ngrok.
In Visual Studio, right-click on your csproj file and go to properties. In there, click on the Debug tab. For convenience, when we are testing, we are going to un-check the Enable SSL checkbox. Take note of the app URL and the port number from the end of it.
Start Ngrok
Next, we'll start up ngrok. We'll point incoming requests to the port from our app URL, and we will have the host and port replace the incoming host header. Start ngrok by running the following command in a new terminal(replace the port number with your port).
This command will result in your terminal being taken over by ngrok. It will show you a URL accessing that URL will forward requests to your local server. This URL will be of the form http://randomhash.ngrok.io
. My random hash came up d98024d97b04
, so for the remainder of this explainer, just replace that value with whatever value came up for yours.
After starting up my app in IIS Express, I can navigate to my ngrok URL to ensure that it's publicly accessible.
Configure Webhooks
If you'll recall, we annotated our InboundSms
method in our SmsController
with [HttpPost("webhooks/inbound-sms")]
this establishes a route for me to http://d98024d97b04.ngrok.io/webhooks/inbound-sms
to make the call to inbound-sms. The last thing I need to do before I'm off and testing is to tell the Vonage where to send my SMS messages to the URL I just mentioned.
To do this, let's navigate to ${CUSTOMER_DASHBOARD_URL}/settings. Under Default SMS Settings, set the Inbound Messages field to that URL, and change the HTTP Method to POST-JSON
. Click Save Changes, and we're ready to test. Navigate to your home page and go ahead and send your Vonage API Virtual number a test message. If you're not sure what your Vonage Virtual Number is, you can find it in your dashboard under numbers. After messaging the server, you'll see the SMS messages come into your server in real-time by watching the web page associated with the app.
And that's all we need to do to receive messages and display them in real-time!
Resources
All the code for this demo can be found in GitHub