SMS and MMS Notifications with C# and ASP.NET MVC

Download the Code

Need to hail your server administrators when something goes wrong with your servers?  We've got you covered - today we'll cover adding notifications on server exceptions to your C# ASP.NET MVC application.  We'll cover all the key plumbing to make it happen!

See how EMC uses Twilio SMS to send IT alerts to 68,000 employees.

Why wait? Click the button below to move to the next step of the tutorial.

List The Server Administrators - and Whomever Else to Contact

Here we create a list of administrators who should be notified if a server error occurs. The only essential piece of data we need is a PhoneNumber for each administrator.

ServerNotifications.Web/App_Data/administrators.csv
CSV list of phone numbers to notify

ServerNotifications.Web/App_Data/administrators.csv

With this list in hand, let's configure the Twilio REST client and see how we use it to send a notification on application exceptions.

Configure the Twilio C# REST Client

To send a message, we'll need to initialize the Twilio C# Helper Library. This requires reading our TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN defined at ServerNotifications.Web/Web.config

Loading Code Samples...
Language
using System.Collections.Generic;
using System;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.Clients;
using System.Threading.Tasks;

namespace ServerNotifications.Web.Domain.Twilio
{
    public interface IRestClient
    {
        Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl);
    }

    public class RestClient : IRestClient
    {
        private readonly ITwilioRestClient _client;

        public RestClient()
        {
            _client = new TwilioRestClient(
                Credentials.TwilioAccountSid,
                Credentials.TwilioAuthToken
            );
        }

        public RestClient(ITwilioRestClient client)
        {
            _client = client;
        }

        public async Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl)
        {
            var toPhoneNumber = new PhoneNumber(to);
            return await MessageResource.CreateAsync(
                toPhoneNumber,
                from: new PhoneNumber(from),
                body: body,
                mediaUrl: mediaUrl,
                client: _client);
        }
    }
}
ServerNotifications.Web/Domain/Twilio/RestClient.cs
Twilio Client Wrapper

ServerNotifications.Web/Domain/Twilio/RestClient.cs

Now that we have our Twilio Client setup, let's see how to handle exceptions.

Handle All C# Application Exceptions

In an ASP.NET MVC application, we can handle errors at the application level. Note that any other exceptions caught in the code (using your own try/catch blocks) are not being captured and processed here.

Loading Code Samples...
Language
SDK Version:
  • asax
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using ServerNotifications.Web.Domain;
using ServerNotifications.Web.Models.Repository;

namespace ServerNotifications.Web
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        protected async void Application_Error(object sender, EventArgs e)
        {
            var exception = Server.GetLastError();
            var message = string.Format("[This is a test] ALERT!" +
                "It appears the server is having issues." +
                "Exception: {0}. Go to: http://newrelic.com for more details.", exception.Message);

            var notifier = new Notifier(new AdministratorsRepository());
            await notifier.SendMessagesAsync(message);
        }
    }
}
ServerNotifications.Web/Global.asax.cs
Catch any uncaught exception raised in the application

ServerNotifications.Web/Global.asax.cs

Any uncaught exception will be handled here. Let's see how we can use this exception to hail our administrator list.

Creating a Custom Alert Message

Here we create an alert message to send out via text message. You might also decide to include a picture with your alert message... maybe a screenshot of the application when the crash happened?  A meme to calm everyone down?

Loading Code Samples...
Language
SDK Version:
  • asax
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using ServerNotifications.Web.Domain;
using ServerNotifications.Web.Models.Repository;

namespace ServerNotifications.Web
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        protected async void Application_Error(object sender, EventArgs e)
        {
            var exception = Server.GetLastError();
            var message = string.Format("[This is a test] ALERT!" +
                "It appears the server is having issues." +
                "Exception: {0}. Go to: http://newrelic.com for more details.", exception.Message);

            var notifier = new Notifier(new AdministratorsRepository());
            await notifier.SendMessagesAsync(message);
        }
    }
}
ServerNotifications.Web/Global.asax.cs
Send a notification to the administrators for an uncaught exception

ServerNotifications.Web/Global.asax.cs

The error handling is setup to capture application wide errors and forward them to all the lucky administrators.

Let’s take a closer look at how the Notifier forwards these errors to the administrators.

Read the Administrators from the CSV File

With CSVReader, we can open and parse our list of administrators from our CSV file. We use the method GetRecords to read all the records.

Loading Code Samples...
Language
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using CsvHelper;

namespace ServerNotifications.Web.Models.Repository
{
    public interface IAdministratorsRepository
    {
        IList<Administrator> All();
    }

    public class AdministratorsRepository : IAdministratorsRepository
    {
        public IList<Administrator> All()
        {
            using (var streamReader = new StreamReader(HttpContext.Current.Server.MapPath("~/App_Data/administrators.csv")))
            {
                var reader = new CsvReader(streamReader);
                return reader.GetRecords<Administrator>().ToList();
            }
        }
    }
}
ServerNotifications.Web/Models/Repository/AdministratorsRepository.cs
Open and parse our administrator list

ServerNotifications.Web/Models/Repository/AdministratorsRepository.cs

We've seen how to load a list of administrators from a file. Now let's see how to send a message to each of them.

Send a Text Message Blast

There are the three parameters needed to send an SMS using the Twilio REST API: From, To, and Body.

US and Canadian phone numbers can also send an image with the message.  (Other countries can as well, but a shortened URL pointing to the image will be appended).

Loading Code Samples...
Language
using System.Collections.Generic;
using System;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.Clients;
using System.Threading.Tasks;

namespace ServerNotifications.Web.Domain.Twilio
{
    public interface IRestClient
    {
        Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl);
    }

    public class RestClient : IRestClient
    {
        private readonly ITwilioRestClient _client;

        public RestClient()
        {
            _client = new TwilioRestClient(
                Credentials.TwilioAccountSid,
                Credentials.TwilioAuthToken
            );
        }

        public RestClient(ITwilioRestClient client)
        {
            _client = client;
        }

        public async Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl)
        {
            var toPhoneNumber = new PhoneNumber(to);
            return await MessageResource.CreateAsync(
                toPhoneNumber,
                from: new PhoneNumber(from),
                body: body,
                mediaUrl: mediaUrl,
                client: _client);
        }
    }
}
ServerNotifications.Web/Domain/Twilio/RestClient.cs
Uses the Twilio Client to send a message

ServerNotifications.Web/Domain/Twilio/RestClient.cs

That's it! We've just implemented an automated server notification system that can send out C# ASP.NET MVC server alerts if anything goes wrong.

Let's see some other fine features you can add to your application, next.

Where to Next?

Twilio and C# are great together!  Here are two more ideas for useful features:

Two-Factor Authentication

Increase the security of your login system by verifying a user's mobile phone in addition to their password.

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! Tweet us @twilio to let us know what you've built... and what you're building.

Agustin Camino
Paul Kamp
Hector Ortega
Andrew Baker
Samuel Mendes
Jose Oliveros

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...
Name,PhoneNumber
Bob,+12025550135
Alice,+12025550181
using System.Collections.Generic;
using System;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.Clients;
using System.Threading.Tasks;

namespace ServerNotifications.Web.Domain.Twilio
{
    public interface IRestClient
    {
        Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl);
    }

    public class RestClient : IRestClient
    {
        private readonly ITwilioRestClient _client;

        public RestClient()
        {
            _client = new TwilioRestClient(
                Credentials.TwilioAccountSid,
                Credentials.TwilioAuthToken
            );
        }

        public RestClient(ITwilioRestClient client)
        {
            _client = client;
        }

        public async Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl)
        {
            var toPhoneNumber = new PhoneNumber(to);
            return await MessageResource.CreateAsync(
                toPhoneNumber,
                from: new PhoneNumber(from),
                body: body,
                mediaUrl: mediaUrl,
                client: _client);
        }
    }
}
SDK Version:
  • asax
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using ServerNotifications.Web.Domain;
using ServerNotifications.Web.Models.Repository;

namespace ServerNotifications.Web
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        protected async void Application_Error(object sender, EventArgs e)
        {
            var exception = Server.GetLastError();
            var message = string.Format("[This is a test] ALERT!" +
                "It appears the server is having issues." +
                "Exception: {0}. Go to: http://newrelic.com for more details.", exception.Message);

            var notifier = new Notifier(new AdministratorsRepository());
            await notifier.SendMessagesAsync(message);
        }
    }
}
SDK Version:
  • asax
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using ServerNotifications.Web.Domain;
using ServerNotifications.Web.Models.Repository;

namespace ServerNotifications.Web
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        protected async void Application_Error(object sender, EventArgs e)
        {
            var exception = Server.GetLastError();
            var message = string.Format("[This is a test] ALERT!" +
                "It appears the server is having issues." +
                "Exception: {0}. Go to: http://newrelic.com for more details.", exception.Message);

            var notifier = new Notifier(new AdministratorsRepository());
            await notifier.SendMessagesAsync(message);
        }
    }
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using CsvHelper;

namespace ServerNotifications.Web.Models.Repository
{
    public interface IAdministratorsRepository
    {
        IList<Administrator> All();
    }

    public class AdministratorsRepository : IAdministratorsRepository
    {
        public IList<Administrator> All()
        {
            using (var streamReader = new StreamReader(HttpContext.Current.Server.MapPath("~/App_Data/administrators.csv")))
            {
                var reader = new CsvReader(streamReader);
                return reader.GetRecords<Administrator>().ToList();
            }
        }
    }
}
using System.Collections.Generic;
using System;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.Clients;
using System.Threading.Tasks;

namespace ServerNotifications.Web.Domain.Twilio
{
    public interface IRestClient
    {
        Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl);
    }

    public class RestClient : IRestClient
    {
        private readonly ITwilioRestClient _client;

        public RestClient()
        {
            _client = new TwilioRestClient(
                Credentials.TwilioAccountSid,
                Credentials.TwilioAuthToken
            );
        }

        public RestClient(ITwilioRestClient client)
        {
            _client = client;
        }

        public async Task<MessageResource> SendMessage(string from, string to, string body, List<Uri> mediaUrl)
        {
            var toPhoneNumber = new PhoneNumber(to);
            return await MessageResource.CreateAsync(
                toPhoneNumber,
                from: new PhoneNumber(from),
                body: body,
                mediaUrl: mediaUrl,
                client: _client);
        }
    }
}