Skip to content

Instantly share code, notes, and snippets.

@Swimburger
Last active December 14, 2022 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Swimburger/2ed883c2aa9e5cae2343527ccf9227b2 to your computer and use it in GitHub Desktop.
Save Swimburger/2ed883c2aa9e5cae2343527ccf9227b2 to your computer and use it in GitHub Desktop.
Two different ways of doing catch-all exception handling, one for MVC only using an exception filter, one using exception handler middleware
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Twilio.AspNet.Core;
using Twilio.TwiML;
namespace TwimlErrorMessageAttribute.Controllers;
[Route("twilio")]
public class TwilioController : Controller
{
[GenericErrorTwimlMessage]
[Route("message")]
public IActionResult Message()
{
var zero = 0;
var result = 1 / zero;
return new MessagingResponse()
.Message($"1/0 is {result}!")
.ToTwiMLResult();
}
[GenericErrorTwimlVoice]
[Route("voice")]
public IActionResult Voice()
{
var zero = 0;
var result = 1 / zero;
return new VoiceResponse()
.Say($"1/0 is {result}!")
.ToTwiMLResult();
}
}
internal enum ErrorTwimlType
{
Message,
Voice
}
public class GenericErrorTwimlMessage : TypeFilterAttribute
{
public GenericErrorTwimlMessage() : base(typeof(GenericErrorTwimlExceptionFilter))
{
Arguments = new[] {(object) ErrorTwimlType.Message};
}
}
public class GenericErrorTwimlVoice : TypeFilterAttribute
{
public GenericErrorTwimlVoice() : base(typeof(GenericErrorTwimlExceptionFilter))
{
Arguments = new[] {(object) ErrorTwimlType.Voice};
}
}
internal class GenericErrorTwimlExceptionFilter : IExceptionFilter
{
private const string GenericErrorMessage = "An unexpected error occurred. Please try again.";
private readonly ILogger<GenericErrorTwimlExceptionFilter> logger;
private readonly ErrorTwimlType twimlType;
public GenericErrorTwimlExceptionFilter(
ILogger<GenericErrorTwimlExceptionFilter> logger,
ErrorTwimlType twimlType
)
{
this.logger = logger;
this.twimlType = twimlType;
}
public void OnException(ExceptionContext context)
{
logger.LogError(context.Exception, "An unhandled exception has occurred while executing the request.");
switch (twimlType)
{
case ErrorTwimlType.Message:
context.Result = new MessagingResponse()
.Message(GenericErrorMessage)
.ToTwiMLResult();
break;
case ErrorTwimlType.Voice:
context.Result = new VoiceResponse()
.Say(GenericErrorMessage)
.ToTwiMLResult();
break;
}
}
}
using Microsoft.AspNetCore.Mvc;
using Twilio.AspNet.Core;
using Twilio.TwiML;
using TwimlErrorMessageAttribute;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseRouting();
app.MapErrorEndpoint();
app.MapControllers();
app.MapGet("/minimal-message", [CatchWithMessageTwiml]() =>
{
var zero = 0;
var result = 1 / zero;
return new MessagingResponse()
.Message($"1/0 is {result}!")
.ToTwiMLResult();
});
app.Run();
public static class ErrorEndpoint
{
private const string GenericErrorMessage = "An unexpected error occurred. Please try again.";
public static IEndpointRouteBuilder MapErrorEndpoint(this IEndpointRouteBuilder builder)
{
builder.Map("/error", OnError);
return builder;
}
private static IResult OnError(HttpContext context)
{
var exceptionFeature = context.Features.Get<IExceptionHandlerFeature>();
if (exceptionFeature?.Endpoint is not null)
{
if (exceptionFeature.Endpoint.Metadata.GetMetadata<CatchWithMessageTwimlAttribute>() is not null)
return TwimlMessageError(context.Response);
if (exceptionFeature.Endpoint.Metadata.GetMetadata<CatchWithVoiceTwimlAttribute>() is not null)
return TwimlVoiceError(context.Response);
}
return StatusCodeError();
}
private static IResult StatusCodeError()
=> Results.StatusCode(StatusCodes.Status500InternalServerError);
private static IResult TwimlMessageError(HttpResponse response)
{
response.StatusCode = StatusCodes.Status200OK;
return new MessagingResponse()
.Message(GenericErrorMessage)
.ToTwiMLResult();
}
private static IResult TwimlVoiceError(HttpResponse response)
{
response.StatusCode = StatusCodes.Status200OK;
return new VoiceResponse()
.Say(GenericErrorMessage)
.ToTwiMLResult();
}
}
[Route("twilio")]
public class TwilioController : Controller
{
[CatchWithMessageTwiml]
[Route("message")]
public IActionResult Message()
{
var zero = 0;
var result = 1 / zero;
return new MessagingResponse()
.Message($"1/0 is {result}!")
.ToTwiMLResult();
}
[CatchWithVoiceTwiml]
[Route("voice")]
public IActionResult Voice()
{
var zero = 0;
var result = 1 / zero;
return new VoiceResponse()
.Say($"1/0 is {result}!")
.ToTwiMLResult();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment