Skip to content

Commit 1eabf80

Browse files
authored
Enhance AccessTokenCallback API docs (#3339)
- Added details about how access tokens relate to connection pooling. - Added a missing exception doc to AccessToken.
1 parent e980d0c commit 1eabf80

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

doc/samples/SqlConnection_AccessTokenCallback.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System;
21
// <Snippet1>
2+
using System;
33
using System.Collections.Concurrent;
44
using System.Threading;
55
using System.Threading.Tasks;
@@ -17,10 +17,10 @@ static void Main()
1717

1818
const string defaultScopeSuffix = "/.default";
1919

20-
// Reuse credential objects to take advantage of underlying token caches
20+
// Reuse credential objects to take advantage of underlying token caches.
2121
private static ConcurrentDictionary<string, DefaultAzureCredential> credentials = new ConcurrentDictionary<string, DefaultAzureCredential>();
2222

23-
// Use a shared callback function for connections that should be in the same connection pool
23+
// Use a shared callback function for connections that should be in the same connection pool.
2424
private static Func<SqlAuthenticationParameters, CancellationToken, Task<SqlAuthenticationToken>> myAccessTokenCallback =
2525
async (authParams, cancellationToken) =>
2626
{
@@ -31,7 +31,7 @@ static void Main()
3131
DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions();
3232
options.ManagedIdentityClientId = authParams.UserId;
3333

34-
// Reuse the same credential object if we are using the same MI Client Id
34+
// Reuse the same credential object if we are using the same MI Client Id.
3535
AccessToken token = await credentials.GetOrAdd(authParams.UserId, new DefaultAzureCredential(options)).GetTokenAsync(
3636
new TokenRequestContext(new string[] { scope }),
3737
cancellationToken);

doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,35 @@ The following example creates a <xref:Microsoft.Data.SqlClient.SqlCommand> and a
236236
<value>
237237
The access token for the connection.
238238
</value>
239+
<exception cref="T:System.InvalidOperationException">
240+
The <see cref="P:Microsoft.Data.SqlClient.SqlConnection.AccessToken" />
241+
is combined with other conflicting authentication configurations.
242+
</exception>
239243
<remarks>
240-
The AccessToken is a part of the connection pool key. Care should be taken when using this property to manage your own access token. The application is responsible for knowing when the token expires and connections from the pool should no longer be used. If you set a minimum pool size > 0 along with AccessToken, you must call <see cref="M:Microsoft.Data.SqlClient.SqlConnection.ClearPool(Microsoft.Data.SqlClient.SqlConnection)" /> after the access token expires to ensure the connection pool doesn't maintain those connections indefinitely.
244+
<para>
245+
The AccessToken is a part of the connection pool key. Supplying a
246+
refreshed access token to a new connection, with all other properties
247+
the same as other existing connections, will place that new connection
248+
into a new pool. Care should be taken when using this property to
249+
manage your own access token. Consider using the
250+
<see cref="P:Microsoft.Data.SqlClient.SqlConnection.AccessTokenCallback" />
251+
property instead, which will not consider refreshed access tokens as
252+
distinct for the purposes of connection pooling.
253+
</para>
254+
<para>
255+
The application is responsible for knowing when the access token
256+
expires and the connections from the pool should no longer be used. If
257+
you set a minimum pool size &gt; 0 along with an AccessToken, you must
258+
call
259+
<see cref="M:Microsoft.Data.SqlClient.SqlConnection.ClearPool(Microsoft.Data.SqlClient.SqlConnection)" />
260+
after the access token expires to ensure the connection pool doesn't
261+
maintain the physical connections (created by the pool) indefinitely.
262+
</para>
263+
<para>
264+
This property is mutually exclusive with the
265+
<see cref="P:Microsoft.Data.SqlClient.SqlConnection.AccessTokenCallback" />
266+
property, among others.
267+
</para>
241268
</remarks>
242269
</AccessToken>
243270
<AccessTokenCallback>
@@ -271,10 +298,10 @@ The following example creates a <xref:Microsoft.Data.SqlClient.SqlCommand> and a
271298

272299
const string defaultScopeSuffix = "/.default";
273300

274-
// Reuse credential objects to take advantage of underlying token caches
301+
// Reuse credential objects to take advantage of underlying token caches.
275302
private static ConcurrentDictionar&lt;string, DefaultAzureCredential&gt; credentials = new ConcurrentDictionary&lt;string, DefaultAzureCredential&gt;();
276303

277-
// Use a shared callback function for connections that should be in the same connection pool
304+
// Use a shared callback function for connections that should be in the same connection pool.
278305
private static Func&lt;SqlAuthenticationParameters, CancellationToken, Task&lt;SqlAuthenticationToken&gt;&gt; myAccessTokenCallback =
279306
async (authParams, cancellationToken) =>
280307
{
@@ -285,7 +312,7 @@ The following example creates a <xref:Microsoft.Data.SqlClient.SqlCommand> and a
285312
DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions();
286313
options.ManagedIdentityClientId = authParams.UserId;
287314

288-
// Reuse the same credential object if we are using the same MI Client ID
315+
// Reuse the same credential object if we are using the same MI Client ID.
289316
AccessToken token = await credentials.GetOrAdd(authParams.UserId, new DefaultAzureCredential(options)).GetTokenAsync(
290317
new TokenRequestContext(new string[] { scope }),
291318
cancellationToken);
@@ -317,6 +344,26 @@ The following example creates a <xref:Microsoft.Data.SqlClient.SqlCommand> and a
317344
<exception cref="T:System.InvalidOperationException">
318345
The <see cref="P:Microsoft.Data.SqlClient.SqlConnection.AccessTokenCallback" /> is combined with other conflicting authentication configurations.
319346
</exception>
347+
<remarks>
348+
<para>
349+
The AccessTokenCallback function itself is a part of the connection
350+
pool key. The same callback function should always provide a valid
351+
access token of the same security context given the same
352+
SqlAuthenticationParameters. When multiple connections use the same
353+
callback function, and all other properties that comprise the pool key
354+
are the same, they will be grouped into the same connection pool.
355+
</para>
356+
<para>
357+
When using a token callback function, the connection manages
358+
refreshing the tokens returned by the callback. The application is
359+
not responsible for knowing when tokens expire.
360+
</para>
361+
<para>
362+
This property is mutually exclusive with the
363+
<see cref="P:Microsoft.Data.SqlClient.SqlConnection.AccessToken" />
364+
property, among others.
365+
</para>
366+
</remarks>
320367
</AccessTokenCallback>
321368
<BeginDbTransaction>
322369
<param name="isolationLevel">

0 commit comments

Comments
 (0)