Skip to content

Commit 3b8b0cd

Browse files
committed
add APIs for working with the connection pools and client-id
1 parent 16ed3fd commit 3b8b0cd

File tree

2 files changed

+187
-1
lines changed

2 files changed

+187
-1
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Data.Common;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
7+
namespace Dapper.ProviderTools
8+
{
9+
/// <summary>
10+
/// Helper utilties for working with database connections
11+
/// </summary>
12+
public static class DbConnectionExtensions
13+
{
14+
/// <summary>
15+
/// Attempt to get the client connection id for a given connection
16+
/// </summary>
17+
public static bool TryGetClientConnectionId(this DbConnection connection, out Guid clientConnectionId)
18+
{
19+
clientConnectionId = default;
20+
return connection != null && ByTypeHelpers.Get(connection.GetType()).TryGetClientConnectionId(
21+
connection, out clientConnectionId);
22+
}
23+
24+
/// <summary>
25+
/// Clear all pools associated with the provided connection type
26+
/// </summary>
27+
public static bool TryClearAllPools(this DbConnection connection)
28+
=> connection != null && ByTypeHelpers.Get(connection.GetType()).TryClearAllPools();
29+
30+
/// <summary>
31+
/// Clear the pools associated with the provided connection
32+
/// </summary>
33+
public static bool TryClearPool(this DbConnection connection)
34+
=> connection != null && ByTypeHelpers.Get(connection.GetType()).TryClearPool(connection);
35+
36+
private sealed class ByTypeHelpers
37+
{
38+
private static readonly ConcurrentDictionary<Type, ByTypeHelpers> s_byType
39+
= new ConcurrentDictionary<Type, ByTypeHelpers>();
40+
private readonly Func<DbConnection, Guid>? _getClientConnectionId;
41+
42+
private readonly Action<DbConnection>? _clearPool;
43+
private readonly Action? _clearAllPools;
44+
45+
public bool TryGetClientConnectionId(DbConnection connection, out Guid clientConnectionId)
46+
{
47+
if (_getClientConnectionId == null)
48+
{
49+
clientConnectionId = default;
50+
return false;
51+
}
52+
clientConnectionId = _getClientConnectionId(connection);
53+
return true;
54+
}
55+
56+
public bool TryClearPool(DbConnection connection)
57+
{
58+
if (_clearPool == null) return false;
59+
_clearPool(connection);
60+
return true;
61+
}
62+
63+
public bool TryClearAllPools()
64+
{
65+
if (_clearAllPools == null) return false;
66+
_clearAllPools();
67+
return true;
68+
}
69+
70+
public static ByTypeHelpers Get(Type type)
71+
{
72+
if (!s_byType.TryGetValue(type, out var value))
73+
{
74+
s_byType[type] = value = new ByTypeHelpers(type);
75+
}
76+
return value;
77+
}
78+
79+
private ByTypeHelpers(Type type)
80+
{
81+
_getClientConnectionId = TryGetInstanceProperty<Guid>("ClientConnectionId", type);
82+
83+
try
84+
{
85+
var clearAllPools = type.GetMethod("ClearAllPools", BindingFlags.Public | BindingFlags.Static,
86+
null, Type.EmptyTypes, null);
87+
if (clearAllPools != null)
88+
{
89+
_clearAllPools = (Action)Delegate.CreateDelegate(typeof(Action), clearAllPools);
90+
}
91+
}
92+
catch { }
93+
94+
try
95+
{
96+
var clearPool = type.GetMethod("ClearPool", BindingFlags.Public | BindingFlags.Static,
97+
null, new[] { type }, null);
98+
if (clearPool != null)
99+
{
100+
var p = Expression.Parameter(typeof(DbConnection), "connection");
101+
var body = Expression.Call(clearPool, Expression.Convert(p, type));
102+
var lambda = Expression.Lambda<Action<DbConnection>>(body, p);
103+
_clearPool = lambda.Compile();
104+
}
105+
}
106+
catch { }
107+
}
108+
109+
private static Func<DbConnection, T>? TryGetInstanceProperty<T>(string name, Type type)
110+
{
111+
try
112+
{
113+
var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
114+
if (prop == null || !prop.CanRead) return null;
115+
if (prop.PropertyType != typeof(T)) return null;
116+
117+
var p = Expression.Parameter(typeof(DbConnection), "connection");
118+
var body = Expression.Property(Expression.Convert(p, type), prop);
119+
var lambda = Expression.Lambda<Func<DbConnection, T>>(body, p);
120+
return lambda.Compile();
121+
}
122+
catch
123+
{
124+
return null;
125+
}
126+
}
127+
}
128+
}
129+
}

Dapper.Tests/ProviderTests.cs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Data.Common;
1+
using System;
2+
using System.Data.Common;
23
using Dapper.ProviderTools;
34
using Xunit;
45

@@ -24,6 +25,62 @@ public void BulkCopy_MicrosoftDataSqlClient()
2425
}
2526
}
2627

28+
[Fact]
29+
public void ClientId_SystemDataSqlClient()
30+
=> TestClientId<SystemSqlClientProvider>();
31+
32+
[Fact]
33+
public void ClientId_MicrosoftDataSqlClient()
34+
=> TestClientId<MicrosoftSqlClientProvider>();
35+
36+
37+
[Fact]
38+
public void ClearPool_SystemDataSqlClient()
39+
=> ClearPool<SystemSqlClientProvider>();
40+
41+
[Fact]
42+
public void ClearPool_MicrosoftDataSqlClient()
43+
=> ClearPool<MicrosoftSqlClientProvider>();
44+
45+
[Fact]
46+
public void ClearAllPools_SystemDataSqlClient()
47+
=> ClearAllPools<SystemSqlClientProvider>();
48+
49+
[Fact]
50+
public void ClearAllPools_MicrosoftDataSqlClient()
51+
=> ClearAllPools<MicrosoftSqlClientProvider>();
52+
53+
private static void TestClientId<T>()
54+
where T : SqlServerDatabaseProvider, new()
55+
{
56+
var provider = new T();
57+
using (var conn = provider.GetOpenConnection())
58+
{
59+
Assert.True(conn.TryGetClientConnectionId(out var id));
60+
Assert.NotEqual(Guid.Empty, id);
61+
}
62+
}
63+
64+
private static void ClearPool<T>()
65+
where T : SqlServerDatabaseProvider, new()
66+
{
67+
var provider = new T();
68+
using (var conn = provider.GetOpenConnection())
69+
{
70+
Assert.True(conn.TryClearPool());
71+
}
72+
}
73+
74+
private static void ClearAllPools<T>()
75+
where T : SqlServerDatabaseProvider, new()
76+
{
77+
var provider = new T();
78+
using (var conn = provider.GetOpenConnection())
79+
{
80+
Assert.True(conn.TryClearAllPools());
81+
}
82+
}
83+
2784
private static void Test<T>(DbConnection connection)
2885
{
2986
using (var bcp = BulkCopy.TryCreate(connection))

0 commit comments

Comments
 (0)