Skip to content

Commit eba5055

Browse files
authored
Merge pull request #85 from twilio-labs/update-docs
Document 6.0.0 features & changes
2 parents aa9c05b + 0eb0d09 commit eba5055

File tree

2 files changed

+248
-14
lines changed

2 files changed

+248
-14
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 6.0.0 (2022-08-05)
2+
- Big breaking change to the `[ValidateRequest]` attribute. The attribute no longer accepts parameters nor properties. Instead, you have to configure the request validation as documented in the readme.
3+
- You can now add the Twilio REST client to ASP.NET Core's dependency injection container, using the `.AddTwilioClient` method. This Twilio client will use an `HttpClient` provided by an HTTP client factory. See readme for more details.
4+
- We no longer try to match the Twilio SDK version number, and instead go by our own versioning to better communicate breaking changes vs minor changes.
5+
- The projects are now built and packages are now pushed using GitHub Actions instead of AppVeyor.
6+
- The projects are now built deterministically and support source link for better debugging.
7+
- More samples have been added to the readme.
8+
19
## 5.77.0 (2022-07-19)
210
- Twilio.AspNet.Core and Twilio.AspNet.Common now use .NET Standard 2.0 and dropped older .NET Standard versions.
311
- Microsoft.AspNetCore.Mvc.Core dependency has been updated to a version that is not vulnerable. For newer versions of .NET, a framework dependency is used instead.

README.md

+240-14
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
**The Twilio helper library for ASP.NET (Twilio.AspNet), helps you integrate the official [Twilio SDK for C# and .NET](https://github.com/twilio/twilio-csharp) into your ASP.NET applications.** The library supports ASP.NET MVC on .NET Framework and ASP.NET Core.
66

7-
You only need this library if you wish to respond to Twilio webhooks for
8-
voice calls and SMS messages. If you only need to use the Twilio REST API's,
9-
then you only need the [Twilio SDK for C# and .NET](https://github.com/twilio/twilio-csharp).
7+
This library helps you respond to webhooks, adds the Twilio client to the dependency injection container, and validate HTTP request originate from Twilio.
108

119
## Twilio.AspNet.Core
1210
[![NuGet Badge](https://buildstats.info/nuget/Twilio.AspNet.Core)](https://www.nuget.org/packages/Twilio.AspNet.Core/)
@@ -55,10 +53,7 @@ public class SmsController : TwilioController
5553
public TwiMLResult Index(SmsRequest request)
5654
{
5755
var response = new MessagingResponse();
58-
response.Message(
59-
$"Hey there {request.From}! " +
60-
"How 'bout those Seahawks?"
61-
);
56+
response.Message($"Ahoy {request.From}!");
6257
return TwiML(response);
6358
}
6459
}
@@ -79,7 +74,7 @@ public class VoiceController : TwilioController
7974
public TwiMLResult Index(VoiceRequest request)
8075
{
8176
var response = new VoiceResponse();
82-
response.Say($"Welcome. Are you from {request.FromCity}?");
77+
response.Say($"Ahoy! Are you from {request.FromCity}?");
8378
return TwiML(response);
8479
}
8580
}
@@ -102,10 +97,7 @@ public class SmsController : Controller
10297
public TwiMLResult Index(SmsRequest request)
10398
{
10499
var response = new MessagingResponse();
105-
response.Message(
106-
$"Hey there {request.From}! " +
107-
"How 'bout those Seahawks?"
108-
);
100+
response.Message($"Ahoy {request.From}!");
109101
return this.TwiML(response);
110102
}
111103
}
@@ -142,6 +134,7 @@ app.MapPost("/sms", async (HttpRequest request) =>
142134

143135
app.Run();
144136
```
137+
145138
In traditional MVC controllers, the `SmsRequest`, `VoiceRequest`, and other typed request object would be bound, but Minimal APIs does not support the same model binding.
146139

147140
Instead, you can bind individual parameters for HTTP GET requests using the `FromQuery` attribute. When you don't specify the [FromQuery](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis#parameter-binding) attribute, multiple sources will be considered to bind from in addition to the query string parameters. For HTTP POST requests you can grab the form and then retrieve individual parameters by string index.
@@ -155,7 +148,8 @@ Here's the list of classes:
155148
- `StatusCallbackRequest`: Holds data for tracking the status of an outbound Twilio Voice Call
156149
- `VoiceRequest`: Holds data for incoming Voice Calls
157150

158-
Note: Only MVC Controllers and Razor Pages supports model binding to typed .NET objects. In Minimal APIs and other scenario's, you'll have to write code to extract the parameters yourself.
151+
> **Note**
152+
> Only MVC Controllers and Razor Pages support model binding to typed .NET objects. In Minimal APIs and other scenarios, you'll have to write code to extract the parameters yourself.
159153
160154
The following sample shows how to accept inbound SMS, respond, and track the status of the SMS response.
161155

@@ -177,7 +171,7 @@ public class SmsController : TwilioController
177171
{
178172
var messagingResponse = new MessagingResponse();
179173
messagingResponse.Message(
180-
body: $"Hey there {request.From}! How 'bout those Seahawks?",
174+
body: $"Ahoy {request.From}!",
181175
action: new Uri("/Sms/StatusCallback"),
182176
method: Twilio.Http.HttpMethod.Post
183177
);
@@ -193,3 +187,235 @@ public class SmsController : TwilioController
193187

194188
As shown in the sample above, you can add an `SmsRequest` as a parameter, and MVC will bind the object for you.
195189
The code then responds with an SMS with the `status` and `method` parameter. When the status of the SMS changes, Twilio will send an HTTP POST request to `StatusCallback` action. You can add an `SmsStatusCallbackRequest` as a parameter, and MVC will bind the object for you.
190+
191+
### Add the Twilio client to the ASP.NET Core dependency injection container
192+
193+
In ASP.NET Core, you can add the Twilio REST API client to ASP.NET Core's service using the `.AddTwilioClient` method, like this:
194+
195+
```csharp
196+
using Twilio.AspNet.Core;
197+
198+
var builder = WebApplication.CreateBuilder(args);
199+
200+
builder.Services.AddTwilioClient()
201+
```
202+
203+
Now you can request `ITwilioRestClient` and `TwilioRestClient` via dependency injection.
204+
205+
You can configure the Twilio client using the following configuration:
206+
207+
```json
208+
{
209+
"Twilio": {
210+
"AuthToken": "[YOUR_AUTH_TOKEN]",
211+
"Client": {
212+
"AccountSid": "[YOUR_ACCOUNT_SID]",
213+
"AuthToken": "[YOUR_AUTH_TOKEN]",
214+
"ApiKeySid": "[YOUR_API_KEY_SID]",
215+
"ApiKeySecret": "[YOUR_API_KEY_SECRET]",
216+
"CredentialType": "[Unspecified|AuthToken|ApiKey]",
217+
"Region": null,
218+
"Edge": null,
219+
"LogLevel": null
220+
}
221+
}
222+
}
223+
```
224+
225+
A couple of notes:
226+
- `Twilio:Client:AuthToken` falls back on `Twilio:AuthToken`. You only need to configure one of them.
227+
- `Twilio:Client:CredentialType` has the following valid values: `Unspecified`, `AuthToken`, or `ApiKey`
228+
- `Twilio:Client:CredentialType` is optional and defaults to `Unspecified`. If `Unspecified`, whether you configured an API key or an Auth Token will be detected.
229+
230+
If you do not wish to configure the Twilio client using .NET configuration, you can do so manually:
231+
232+
```csharp
233+
using Twilio.AspNet.Core;
234+
235+
var builder = WebApplication.CreateBuilder(args);
236+
237+
builder.Services
238+
.AddTwilioClient((serviceProvider, options) =>
239+
{
240+
options.AccountSid = "[YOUR_ACCOUNT_SID]";
241+
options.AuthToken = "[YOUR_AUTH_TOKEN]";
242+
options.ApiKeySid = "[YOUR_API_KEY_SID]";
243+
options.ApiKeySecret = "[YOUR_API_KEY_SECRET]";
244+
options.Edge = null;
245+
options.Region = null;
246+
options.LogLevel = null;
247+
options.CredentialType = CredentialType.Unspecified;
248+
});
249+
```
250+
251+
> **Warning**
252+
> Do not hard-code your **Auth Token** or **API key secret** into code and do not check them into source control.
253+
> We recommend using the [Secrets Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets) for local development.
254+
> Alternatively, you can use environment variables, a vault service, or other more secure techniques.
255+
256+
#### Use your own HTTP client
257+
258+
By default when you call `.AddTwilioClient`, an HTTP client factory is configured that is used to provide an `HttpClient` to the Twilio REST client. If you'd like to provide your own HTTP client, you can do so by providing a callback like this:
259+
260+
```csharp
261+
```csharp
262+
using Twilio.AspNet.Core;
263+
264+
var builder = WebApplication.CreateBuilder(args);
265+
266+
builder.Services.AddTwilioClient(provider => new HttpClient())
267+
```
268+
269+
### Validate Twilio HTTP requests
270+
271+
Webhooks require your endpoint to be publicly available, but this also introduces the risk that bad actors could find your webhook URL and try to abuse it.
272+
273+
Luckily, you can verify that an HTTP request originated from Twilio.
274+
The `Twilio.AspNet` library provides an attribute that will validate the request for you in MVC.
275+
The implementation differs between the `Twilio.AspNet.Core` and `Twilio.AspNet.Mvc` library.
276+
277+
#### Validate requests in ASP.NET Core MVC
278+
279+
Add the `.AddTwilioRequestValidation` method at startup:
280+
281+
```csharp
282+
using Twilio.AspNet.Core;
283+
284+
var builder = WebApplication.CreateBuilder(args);
285+
286+
builder.Services.AddTwilioRequestValidation();
287+
```
288+
289+
Then configure the request validation:
290+
291+
```json
292+
{
293+
"Twilio": {
294+
"AuthToken": "[YOUR_AUTH_TOKEN]",
295+
"RequestValidation": {
296+
"AuthToken": "[YOUR_AUTH_TOKEN]",
297+
"AllowLocal": true,
298+
"BaseUrlOverride": "https://??????.ngrok.io"
299+
}
300+
}
301+
}
302+
```
303+
304+
A couple of notes about the configuration:
305+
- `Twilio:RequestValidation:AuthToken` falls back on `Twilio:AuthToken`. You only need to configure one of them.
306+
- `AllowLocal` will skip validation when the HTTP request originated from localhost.
307+
- Use `BaseUrlOverride` in case your app is behind a reverse proxy or a tunnel like ngrok. The path of the current request will be appended to the `BaseUrlOverride` for request validation.
308+
309+
You can also manually configure the request validation:
310+
311+
```csharp
312+
using Twilio.AspNet.Core;
313+
314+
var builder = WebApplication.CreateBuilder(args);
315+
316+
builder.Services
317+
.AddTwilioRequestValidation((serviceProvider, options) =>
318+
{
319+
options.AuthToken = "[YOUR_AUTH_TOKEN]";
320+
options.AllowLocal = true;
321+
options.BaseUrlOverride = "https://??????.ngrok.io";
322+
});
323+
```
324+
325+
> **Warning**
326+
> Do not hard-code your **Auth Token** into code and do not check them into source control.
327+
> We recommend using the [Secrets Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets) for local development.
328+
> Alternatively, you can use environment variables, a vault service, or other more secure techniques.
329+
330+
Now that request validation has been configured, use the `[ValidateRequest]` attribute.
331+
You can apply the attribute globally, to MVC areas, controllers, and actions.
332+
Here's an example where the attribute is applied to the `Index` action:
333+
334+
```csharp
335+
using Twilio.AspNet.Common;
336+
using Twilio.AspNet.Core;
337+
using Twilio.TwiML;
338+
339+
public class SmsController : TwilioController
340+
{
341+
[ValidateRequest]
342+
public TwiMLResult Index(SmsRequest request)
343+
{
344+
var response = new MessagingResponse();
345+
response.Message("Ahoy!");
346+
return TwiML(response);
347+
}
348+
}
349+
```
350+
351+
#### Validate requests in ASP.NET MVC on .NET Framework
352+
353+
In your _Web.config_ you can configure request validation like shown below:
354+
355+
```xml
356+
<?xml version="1.0" encoding="utf-8"?>
357+
<configuration>
358+
<configSections>
359+
<sectionGroup name="twilio" type="Twilio.AspNet.Mvc.TwilioSectionGroup,Twilio.AspNet.Mvc">
360+
<section name="requestValidation" type="Twilio.AspNet.Mvc.RequestValidationConfigurationSection,Twilio.AspNet.Mvc"/>
361+
</sectionGroup>
362+
</configSections>
363+
<twilio>
364+
<requestValidation
365+
authToken="your auth token here"
366+
baseUrlOverride="https://??????.ngrok.io"
367+
allowLocal="true"
368+
/>
369+
</twilio>
370+
</configuration>
371+
```
372+
373+
You can also configure request validation using app settings:
374+
375+
```xml
376+
<?xml version="1.0" encoding="utf-8"?>
377+
<configuration>
378+
<appSettings>
379+
<add key="twilio:requestValidation:authToken" value="[YOUR_AUTH_TOKEN]"/>
380+
<add key="twilio:requestValidation:baseUrlOverride" value="https://??????.ngrok.io"/>
381+
<add key="twilio:requestValidation:allowLocal" value="true"/>
382+
</appSettings>
383+
</configuration>
384+
```
385+
386+
If you configure request validation using both ways, app setting will overwrite the `twilio/requestValidation` configuration element.
387+
388+
A couple of notes about the configuration:
389+
- `allowLocal` will skip validation when the HTTP request originated from localhost.
390+
- Use `baseUrlOverride` in case you are in front of a reverse proxy or a tunnel like ngrok. The path of the current request will be appended to the `baseUrlOverride` for request validation.
391+
392+
> **Warning**
393+
> Do not hard-code your **Auth Token** into code and do not check them into source control.
394+
> Use the `UserSecretsConfigBuilder` for local development or [one of the other configuration builders](https://docs.microsoft.com/en-us/aspnet/config-builder).
395+
> Alternatively, you should encrypt the configuration sections containing secrets like the Auth Token.
396+
397+
Now that request validation has been configured, use the `[ValidateRequest]` attribute.
398+
You can apply the attribute globally, to MVC areas, controllers, and actions.
399+
Here's an example where the attribute is applied to the `Index` action:
400+
401+
```csharp
402+
using Twilio.AspNet.Common;
403+
using Twilio.AspNet.Mvc;
404+
using Twilio.TwiML;
405+
406+
public class SmsController : TwilioController
407+
{
408+
[ValidateRequest]
409+
public TwiMLResult Index(SmsRequest request)
410+
{
411+
var response = new MessagingResponse();
412+
response.Message("Ahoy!");
413+
return TwiML(response);
414+
}
415+
}
416+
```
417+
418+
#### Validate requests outside of MVC
419+
420+
The `[ValidateRequest]` attribute only works for MVC. If you need to validate requests outside of MVC, you can use the `RequestValidationHelper` class provided by `Twilio.AspNet`.
421+
Alternatively, the `RequestValidator` class from the [Twilio SDK](https://github.com/twilio/twilio-csharp) can also help you with this.

0 commit comments

Comments
 (0)