
La biblioteca Twilio Helper para ASP.NET (Twilio.aspnet) lo ayuda a integrar el SDK oficial Twilio para C# y .NET en sus aplicaciones ASP.NET. La biblioteca admite ASP.NET MVC en .NET Framework y ASP.NET Core.
Esta biblioteca lo ayuda a responder a Webhooks, agrega el cliente Twilio al contenedor de inyección de dependencia y valida la solicitud HTTP se origina en Twilio.
Requiere .NET 6.0 o posterior.
Ejecute el siguiente comando para instalar el paquete con la CLI .NET:
dotnet add package Twilio.AspNet.CoreAlternativamente, desde la consola del administrador de paquetes o el desarrollador PowerShell, ejecute el siguiente comando para instalar la última versión:
Install-Package Twilio.AspNet.CoreAlternativamente, use el Nuget Package Manager para Visual Studio o la ventana Nuget para JetBrains Rider, luego busque twilio.aspnet.core e instale el paquete.
Requiere .NET 4.6.2 o posterior.
Desde la consola del paquete Administrador o el desarrollador PowerShell, ejecute el siguiente comando para instalar la última versión:
Install-Package Twilio.AspNet.MvcAlternativamente, use el Nuget Package Manager para Visual Studio o la ventana Nuget para JetBrains Rider, luego busque twilio.aspnet.mvc e instale el paquete.
using Twilio . AspNet . Common ;
using Twilio . AspNet . Core ; // or .Mvc for .NET Framework
using Twilio . TwiML ;
public class SmsController : TwilioController
{
// GET: Sms
public TwiMLResult Index ( SmsRequest request )
{
var response = new MessagingResponse ( ) ;
response . Message ( $ "Ahoy { request . From } !" ) ;
return TwiML ( response ) ;
}
} Este controlador manejará el SMS Webhook. Los detalles del SMS entrante estarán vinculados al parámetro SmsRequest request . Al heredar desde el TwilioController , obtiene acceso al método TwiML que puede usar para responder con TWIML.
using Twilio . AspNet . Common ;
using Twilio . AspNet . Core ; // or .Mvc for .NET Framework
using Twilio . TwiML ;
public class VoiceController : TwilioController
{
// GET: Voice
public TwiMLResult Index ( VoiceRequest request )
{
var response = new VoiceResponse ( ) ;
response . Say ( $ "Ahoy! Are you from { request . FromCity } ?" ) ;
return TwiML ( response ) ;
}
} Este controlador manejará el webhook de voz. Los detalles de la llamada de voz entrante estarán vinculados al parámetro VoiceRequest request . Al heredar desde el TwilioController , obtiene acceso al método TwiML que puede usar para responder con TWIML.
TwiML en lugar de heredar de TwilioController Si no puede heredar de la clase TwilioController , puede usar los métodos de extensión TwiML .
using Microsoft . AspNetCore . Mvc ; // or System.Web.Mvc for .NET Framework
using Twilio . AspNet . Common ;
using Twilio . AspNet . Core ; // or .Mvc for .NET Framework
using Twilio . TwiML ;
public class SmsController : Controller
{
// GET: Sms
public TwiMLResult Index ( SmsRequest request )
{
var response = new MessagingResponse ( ) ;
response . Message ( $ "Ahoy { request . From } !" ) ;
return this . TwiML ( response ) ;
}
} Esta muestra es la misma que la muestra de webhook de SMS anterior, pero en lugar de heredar de TwilioController , el SmsController hereda del Controller ASP.NET MVC, y usa this.TwiML para usar el método de extensión TwiML .
Twilio.aspnet.core también tiene soporte para API mínimas.
Esta muestra le muestra cómo puede entregar un SMS Webhook usando HTTP Get and Publica.
using Microsoft . AspNetCore . Mvc ;
using Twilio . AspNet . Core . MinimalApi ;
using Twilio . TwiML ;
var builder = WebApplication . CreateBuilder ( args ) ;
var app = builder . Build ( ) ;
app . MapGet ( "/sms" , ( [ FromQuery ] string from ) =>
{
var response = new MessagingResponse ( ) ;
response . Message ( $ "Ahoy { from } !" ) ;
return Results . Extensions . TwiML ( response ) ;
} ) ;
app . MapPost ( "/sms" , async ( HttpRequest request ) =>
{
var form = await request . ReadFormAsync ( ) ;
var from = form [ "from" ] ;
response . Message ( $ "Ahoy { from } !" ) ;
return Results . Extensions . TwiML ( response ) ;
} ) ;
app . Run ( ) ; En los controladores MVC tradicionales, el SmsRequest , VoiceRequest y otro objeto de solicitud mecanografiado estarían obligados, pero las API mínimas no admiten la misma unión del modelo.
En su lugar, puede vincular los parámetros individuales para las solicitudes HTTP utilizando el atributo FromQuery . Cuando no especifique el atributo de Doming, se considerarán múltiples fuentes para que se vinculen de los parámetros de cadena de consulta. Para las solicitudes de publicación HTTP, puede obtener el formulario y luego recuperar los parámetros individuales por índice de cadena.
Para responder con TWIML, use el método Results.Extensions.TwiML .
Twilio.aspnet viene con múltiples clases para ayudarlo a vincular los datos de Webhooks a objetos .NET fuertemente escritos. Aquí está la lista de clases:
SmsRequest : contiene datos para las solicitudes de webhook de SMS entrantesSmsStatusCallbackRequest : contiene datos para rastrear el estado de entrega de un SMS o MMS salienteStatusCallbackRequest : contiene datos para rastrear el estado de una llamada de voz twilio salienteVoiceRequest : posee datos para llamadas de voz entrantesTenga en cuenta solo los controladores MVC y las páginas de afeitar que admiten la unión del modelo a los objetos .NET mecanografiados. En API mínimas y otros escenarios, tendrá que escribir código para extraer los parámetros usted mismo.
La siguiente muestra muestra cómo aceptar SMS entrantes, responder y rastrear el estado de la respuesta SMS.
using Twilio . AspNet . Common ;
using Twilio . AspNet . Core ; // or .Mvc for .NET Framework
using Twilio . TwiML ;
public class SmsController : TwilioController
{
private readonly ILogger < SmsController > logger ;
public SmsController ( ILogger < SmsController > logger )
{
this . logger = logger ;
}
public TwiMLResult Index ( SmsRequest request )
{
var messagingResponse = new MessagingResponse ( ) ;
messagingResponse . Message (
body : $ "Ahoy { request . From } !" ,
action : new Uri ( "/Sms/StatusCallback" ) ,
method : Twilio . Http . HttpMethod . Post
) ;
return TwiML ( messagingResponse ) ;
}
public void StatusCallback ( SmsStatusCallbackRequest request )
{
logger . LogInformation ( "SMS Status: {Status}" , request . MessageStatus ) ;
}
} Como se muestra en la muestra anterior, puede agregar un SmsRequest como parámetro, y MVC se unirá al objeto para usted. El código luego responde con un SMS con el parámetro status y method . Cuando cambia el estado del SMS, Twilio enviará una solicitud de publicación HTTP a la acción StatusCallback . Puede agregar una SmsStatusCallbackRequest como parámetro, y MVC le vinculará el objeto.
En ASP.NET Core, puede agregar el cliente API REST TWILIO a los servicios de ASP.NET Core utilizando el método .AddTwilioClient , como este:
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services . AddTwilioClient ( ) Ahora puede solicitar ITwilioRestClient y TwilioRestClient a través de la inyección de dependencia.
Puede configurar el cliente Twilio utilizando la siguiente configuración:
{
"Twilio" : {
"AuthToken" : " [YOUR_AUTH_TOKEN] " ,
"Client" : {
"AccountSid" : " [YOUR_ACCOUNT_SID] " ,
"AuthToken" : " [YOUR_AUTH_TOKEN] " ,
"ApiKeySid" : " [YOUR_API_KEY_SID] " ,
"ApiKeySecret" : " [YOUR_API_KEY_SECRET] " ,
"CredentialType" : " [Unspecified|AuthToken|ApiKey] " ,
"Region" : null ,
"Edge" : null ,
"LogLevel" : null
}
}
}Un par de notas:
Twilio:Client:AuthToken recurre a Twilio:AuthToken . Solo necesita configurar uno de ellos.Twilio:Client:CredentialType tiene los siguientes valores válidos: Unspecified , AuthToken o ApiKey .Twilio:Client:CredentialType es opcional y el valor predeterminado Unspecified . Si Unspecified , si configuró una clave API o se detectará un token de autenticación.Si no desea configurar el cliente Twilio usando la configuración de .NET, puede hacerlo manualmente:
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddTwilioClient ( ( serviceProvider , options ) =>
{
options . AccountSid = "[YOUR_ACCOUNT_SID]" ;
options . AuthToken = "[YOUR_AUTH_TOKEN]" ;
options . ApiKeySid = "[YOUR_API_KEY_SID]" ;
options . ApiKeySecret = "[YOUR_API_KEY_SECRET]" ;
options . Edge = null ;
options . Region = null ;
options . LogLevel = null ;
options . CredentialType = CredentialType . Unspecified ;
} ) ;ADVERTENCIA No codifique el secreto de su token de autenticación o clave API en el código y no los compruebe para el control de origen. Recomendamos usar el Secrets Manager para el desarrollo local. Alternativamente, puede usar variables de entorno, un servicio de bóveda u otras técnicas más seguras.
De forma predeterminada, cuando llama .AddTwilioClient , se configura una fábrica de clientes HTTP que se utiliza para proporcionar un HttpClient al cliente REST TWILIO. Si desea personalizar este cliente HTTP, puede hacerlo anulando la fábrica de clientes HTTP "Twilio", después de invocar .AddTwilioClient :
builder . Services . AddTwilioClient ( ) ;
builder . Services . AddHttpClient ( "Twilio" )
. ConfigureHttpClient ( client =>
{
client . BaseAddress = new Uri ( "YOUR_PROXY_ADDRESS" ) ;
} )
. ConfigurePrimaryHttpMessageHandler ( ( ) => new HttpClientHandler
{
// same options as the Twilio C# SDK
AllowAutoRedirect = false
} ) ;Los webhooks requieren que su punto final esté disponible públicamente, pero esto también presenta el riesgo de que los malos actores puedan encontrar su URL de Webhook e intentar abusar de ella.
Afortunadamente, puede verificar que una solicitud HTTP se originó en Twilio. La biblioteca Twilio.AspNet proporciona un atributo que validará la solicitud por usted en MVC. La implementación difiere entre Twilio.AspNet.Core y Twilio.AspNet.Mvc biblioteca.
Agregue el método .AddTwilioRequestValidation al inicio:
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services . AddTwilioRequestValidation ( ) ;Luego configure la validación de solicitud:
{
"Twilio" : {
"AuthToken" : " [YOUR_AUTH_TOKEN] " ,
"RequestValidation" : {
"AuthToken" : " [YOUR_AUTH_TOKEN] " ,
"AllowLocal" : false ,
"BaseUrlOverride" : " https://??????.ngrok.io "
}
}
}Un par de notas sobre la configuración:
Twilio:RequestValidation:AuthToken recurre en Twilio:AuthToken . Solo necesita configurar uno de ellos.AllowLocal omitirá la validación cuando la solicitud HTTP se originó en LocalHost.BaseUrlOverride en caso de que su aplicación esté detrás de un proxy inverso o un túnel como NGROK. La ruta de la solicitud actual se agregará al BaseUrlOverride para la validación de la solicitud.Información En lugar de configurar el
BaseUrlOverride, puede usar el middleware de encabezados reenviados para establecer el esquema, el puerto, el host, etc. correctos en la solicitud HTTP actual.
using Microsoft . AspNetCore . HttpOverrides ;
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services . AddTwilioRequestValidation ( ) ;
builder . Services . Configure < ForwardedHeadersOptions > ( options => options . ForwardedHeaders = ForwardedHeaders . All ) ;
// more service configuration
var app = builder . Build ( ) ;
app . UseForwardedHeaders ( ) ;
// more request pipeline configuration
app . Run ( ) ; Como resultado, no tiene que configurar BaseUrlOverride cada vez que reinicie NGROK, o cambie las URL de proxy inversa. Siga la guía de Microsoft para configurar el middleware de encabezado reenviado de forma segura.
También puede configurar manualmente la validación de la solicitud:
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddTwilioRequestValidation ( ( serviceProvider , options ) =>
{
options . AuthToken = "[YOUR_AUTH_TOKEN]" ;
options . AllowLocal = false ;
options . BaseUrlOverride = "https://??????.ngrok.io" ;
} ) ;ADVERTENCIA No codifique su token de autenticación en el código y no los compruebe para el control de la fuente. Recomendamos usar el Secrets Manager para el desarrollo local. Alternativamente, puede usar variables de entorno, un servicio de bóveda u otras técnicas más seguras.
Una vez que se haya configurado la validación de la solicitud, puede usar el atributo [ValidateRequest] en MVC. Puede aplicar el atributo a nivel mundial, a las áreas, controladores y acciones MVC. Aquí hay un ejemplo en el que el atributo se aplica a la acción Index :
using Twilio . AspNet . Common ;
using Twilio . AspNet . Core ;
using Twilio . TwiML ;
public class SmsController : TwilioController
{
[ ValidateRequest ]
public TwiMLResult Index ( SmsRequest request )
{
var response = new MessagingResponse ( ) ;
response . Message ( "Ahoy!" ) ;
return TwiML ( response ) ;
}
} .NET 7 presenta el concepto de filtros de punto final que puede aplicar a cualquier punto final de núcleo ASP.NET. La biblioteca auxiliar de ASP.NET Core agregó un filtro de punto final para validar las solicitudes de Twilio llamadas ValidateTwilioRequestFilter .
Puede agregar este filtro a cualquier grupo de punto final o grupo de punto final utilizando el método ValidateTwilioRequest :
// add filter to endpoint
app . MapPost ( "/sms" , ( ) => .. . )
. ValidateTwilioRequest ( ) ;
// add filter to endpoint group
var twilioGroup = app . MapGroup ( "/twilio" ) ;
twilioGroup . ValidateTwilioRequest ( ) ;
twilioGroup . MapPost ( "/sms" , ( ) => .. . ) ;
twilioGroup . MapPost ( "/voice" , ( ) => .. . ) ;Alternativamente, puede agregar el filtro de punto final usted mismo:
app . MapPost ( "/sms" , ( ) => .. . )
. AddEndpointFilter < ValidateTwilioRequestFilter > ( ) ; Cuando no puede usar el filtro [ValidateRequest] o ValidateTwilioRequestFilter , puede usar ValidateTwilioRequestMiddleware en su lugar. Puede agregar Agregar el ValidateTwilioRequestFilter como este:
app . UseTwilioRequestValidation ( ) ;
// or the equivalent: app.UseMiddleware<ValidateTwilioRequestMiddleware>(); Este middleware realizará la validación para todas las solicitudes. Si no desea aplicar la validación a todas las solicitudes, puede usar app.UseWhen() para ejecutar el middleware condicionalmente.
Aquí hay un ejemplo de cómo validar las solicitudes que comienzan con Rath /Twilio-Media , para proteger los archivos multimedia a los que solo el proxy de Twilio debería poder acceder:
using System . Net ;
using Microsoft . Extensions . FileProviders ;
using Microsoft . Extensions . Options ;
using Twilio . AspNet . Core ;
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services . AddTwilioRequestValidation ( ) ;
var app = builder . Build ( ) ;
app . UseWhen (
context => context . Request . Path . StartsWithSegments ( "/twilio-media" , StringComparison . OrdinalIgnoreCase ) ,
app => app . UseTwilioRequestValidation ( )
) ;
app . UseStaticFiles ( new StaticFileOptions
{
FileProvider = new PhysicalFileProvider ( Path . Combine ( builder . Environment . ContentRootPath , "TwilioMedia" ) ) ,
RequestPath = "/twilio-media"
} ) ;
app . Run ( ) ; En su web.config puede configurar la validación de solicitudes como se muestra a continuación:
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< configuration >
< configSections >
< sectionGroup name = " twilio " type = " Twilio.AspNet.Mvc.TwilioSectionGroup,Twilio.AspNet.Mvc " >
< section name = " requestValidation " type = " Twilio.AspNet.Mvc.RequestValidationConfigurationSection,Twilio.AspNet.Mvc " />
</ sectionGroup >
</ configSections >
< twilio >
< requestValidation
authToken = " [YOUR_AUTH_TOKEN] "
baseUrlOverride = " https://??????.ngrok.io "
allowLocal = " false "
/>
</ twilio >
</ configuration >También puede configurar la validación de solicitud utilizando la configuración de la aplicación:
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< configuration >
< appSettings >
< add key = " twilio:requestValidation:authToken " value = " [YOUR_AUTH_TOKEN] " />
< add key = " twilio:requestValidation:baseUrlOverride " value = " https://??????.ngrok.io " />
< add key = " twilio:requestValidation:allowLocal " value = " false " />
</ appSettings >
</ configuration > Si configura la validación de solicitudes utilizando ambas formas, la configuración de la aplicación sobrescribirá el elemento de configuración de twilio/requestValidation .
Un par de notas sobre la configuración:
allowLocal omitirá la validación cuando la solicitud HTTP se originó en LocalHost.baseUrlOverride en caso de que esté frente a un proxy inverso o un túnel como NGROK. La ruta de la solicitud actual se agregará al baseUrlOverride para la validación de la solicitud.ADVERTENCIA No codifique su token de autenticación en el código y no los compruebe para el control de la fuente. Use
UserSecretsConfigBuilderpara el desarrollo local o uno de los otros constructores de configuración. Alternativamente, debe cifrar las secciones de configuración que contienen secretos como el token de autenticación.
Ahora que se ha configurado la validación de la solicitud, use el atributo [ValidateRequest] . Puede aplicar el atributo a nivel mundial, a las áreas, controladores y acciones MVC. Aquí hay un ejemplo en el que el atributo se aplica a la acción Index :
using Twilio . AspNet . Common ;
using Twilio . AspNet . Mvc ;
using Twilio . TwiML ;
public class SmsController : TwilioController
{
[ ValidateRequest ]
public TwiMLResult Index ( SmsRequest request )
{
var response = new MessagingResponse ( ) ;
response . Message ( "Ahoy!" ) ;
return TwiML ( response ) ;
}
} El atributo [ValidateRequest] solo funciona para MVC. Si necesita validar las solicitudes fuera de MVC, puede usar la clase RequestValidationHelper proporcionada por Twilio.AspNet . Alternativamente, la clase RequestValidator del SDK de Twilio también puede ayudarlo con esto.
Aquí hay un ejemplo mínimo de API que valida la solicitud entrante originada desde Twilio:
using System . Net ;
using Microsoft . Extensions . Options ;
using Twilio . AspNet . Core ;
using Twilio . AspNet . Core . MinimalApi ;
using Twilio . TwiML ;
var builder = WebApplication . CreateBuilder ( args ) ;
// adds TwilioRequestValidationOptions
builder . Services . AddTwilioRequestValidation ( ) ;
var app = builder . Build ( ) ;
app . MapPost ( "/sms" , ( HttpContext httpContext ) =>
{
if ( IsValidTwilioRequest ( httpContext ) == false )
return Results . StatusCode ( ( int ) HttpStatusCode . Forbidden ) ;
var messagingResponse = new MessagingResponse ( ) ;
messagingResponse . Message ( "Ahoy!" ) ;
return Results . Extensions . TwiML ( messagingResponse ) ;
} ) ;
app . Run ( ) ;
bool IsValidTwilioRequest ( HttpContext httpContext )
{
var options = httpContext . RequestServices
. GetService < IOptions < TwilioRequestValidationOptions > > ( )
? . Value ?? throw new Exception ( "TwilioRequestValidationOptions missing." ) ;
string ? urlOverride = null ;
if ( options . BaseUrlOverride is not null )
{
var request = httpContext . Request ;
urlOverride = $ " { options . BaseUrlOverride . TrimEnd ( '/' ) } { request . Path } { request . QueryString } " ;
}
return RequestValidationHelper . IsValidRequest ( httpContext , options . AuthToken , urlOverride , options . AllowLocal ) ;
} AddTwilioRequestValidation agrega el TwilioRequestValidationOptions , que normalmente se usa para el atributo [ValidateRequest] , pero en esta muestra se utiliza para recuperar la configuración de validación de solicitud usted mismo. Luego, dentro del punto final /SMS , el método IsValidTwilioRequest se utiliza para validar la solicitud. IsValidTwilioRequest recupera las opciones de validación de la solicitud de DI y realiza la misma lógica que [ValidateRequest] haría para las solicitudes MVC. Si la solicitud no es válida, se devuelve el código de estado HTTP 403, de lo contrario, algunos dos se devuelven a Twilio.