11using System ;
22using System . Collections . Concurrent ;
3- using System . Collections . Generic ;
4- using System . Linq ;
53using System . Net . Http ;
6- using System . Text ;
74using System . Threading ;
85using System . Threading . Tasks ;
96
@@ -12,32 +9,87 @@ namespace WebApiClient
129 /// <summary>
1310 /// 表示HttpApiClient创建工厂
1411 /// </summary>
15- public class HttpApiClientFactory : IHttpApiClientFactory
12+ public partial class HttpApiClientFactory : IHttpApiClientFactory
1613 {
1714 /// <summary>
18- /// 获取默认的实例
15+ /// handler的生命周期
1916 /// </summary>
20- public static readonly HttpApiClientFactory Default = new HttpApiClientFactory ( ) ;
17+ private TimeSpan lifeTime = TimeSpan . FromMinutes ( 2d ) ;
2118
22- private readonly TimeSpan defaultCleanupInterval = TimeSpan . FromSeconds ( 10d ) ;
19+ /// <summary>
20+ /// 清理handler时间间隔
21+ /// </summary>
22+ private TimeSpan cleanupInterval = TimeSpan . FromSeconds ( 10d ) ;
2323
24+ /// <summary>
25+ /// 过期的记录
26+ /// </summary>
2427 private readonly ConcurrentQueue < ExpiredHandlerEntry > expiredEntries ;
2528
29+ /// <summary>
30+ /// 激活记录的创建工厂
31+ /// </summary>
2632 private readonly Func < Type , Lazy < ActiveHandlerEntry > > activeEntryFactory ;
2733
28- private readonly ConcurrentDictionary < Type , Action < HttpApiConfig > > configs ;
34+ /// <summary>
35+ /// http接口客户端选项
36+ /// </summary>
37+ private readonly ConcurrentDictionary < Type , TypedClientOption > typedClientOptions ;
2938
39+ /// <summary>
40+ /// 激活的记录
41+ /// </summary>
3042 private readonly ConcurrentDictionary < Type , Lazy < ActiveHandlerEntry > > activeEntries ;
3143
3244
33- public TimeSpan Lifetime { get ; set ; } = TimeSpan . FromMinutes ( 2d ) ;
45+ /// <summary>
46+ /// 获取或设置HttpMessageHandler的生命周期
47+ /// </summary>
48+ /// <exception cref="ArgumentOutOfRangeException"></exception>
49+ public TimeSpan Lifetime
50+ {
51+ get
52+ {
53+ return this . lifeTime ;
54+ }
55+ set
56+ {
57+ if ( value <= TimeSpan . Zero )
58+ {
59+ throw new ArgumentOutOfRangeException ( ) ;
60+ }
61+ this . lifeTime = value ;
62+ }
63+ }
3464
65+ /// <summary>
66+ /// 获取或设置清理过期的HttpMessageHandler的时间间隔
67+ /// </summary>
68+ /// <exception cref="ArgumentOutOfRangeException"></exception>
69+ public TimeSpan CleanupInterval
70+ {
71+ get
72+ {
73+ return this . cleanupInterval ;
74+ }
75+ set
76+ {
77+ if ( value <= TimeSpan . Zero )
78+ {
79+ throw new ArgumentOutOfRangeException ( ) ;
80+ }
81+ this . cleanupInterval = value ;
82+ }
83+ }
3584
85+ /// <summary>
86+ /// HttpApiClient创建工厂
87+ /// </summary>
3688 public HttpApiClientFactory ( )
3789 {
3890 this . expiredEntries = new ConcurrentQueue < ExpiredHandlerEntry > ( ) ;
39- this . configs = new ConcurrentDictionary < Type , Action < HttpApiConfig > > ( ) ;
4091 this . activeEntries = new ConcurrentDictionary < Type , Lazy < ActiveHandlerEntry > > ( ) ;
92+ this . typedClientOptions = new ConcurrentDictionary < Type , TypedClientOption > ( ) ;
4193 this . activeEntryFactory = apiType => new Lazy < ActiveHandlerEntry > ( ( ) => this . CreateActiveEntry ( apiType ) , LazyThreadSafetyMode . ExecutionAndPublication ) ;
4294
4395 this . RegisteCleanup ( ) ;
@@ -47,69 +99,102 @@ public HttpApiClientFactory()
4799 /// 注册HttpApiClient对应的http接口
48100 /// </summary>
49101 /// <typeparam name="TInterface"></typeparam>
50- /// <param name="config">配置</param>
51- /// <returns></returns>
52- public bool AddHttpApiClient < TInterface > ( Action < HttpApiConfig > config ) where TInterface : class , IHttpApi
102+ /// <param name="config">HttpApiConfig的配置</param>
103+ /// <param name="handlerFactory">HttpMessageHandler创建委托</param>
104+ /// <exception cref="InvalidOperationException"></exception>
105+ public void AddTypedClient < TInterface > ( Action < HttpApiConfig > config , Func < HttpMessageHandler > handlerFactory ) where TInterface : class , IHttpApi
53106 {
54- return this . configs . TryAdd ( typeof ( TInterface ) , config ) ;
107+ if ( handlerFactory == null )
108+ {
109+ handlerFactory = ( ) => new DefaultHttpClientHandler ( ) ;
110+ }
111+
112+ var options = new TypedClientOption
113+ {
114+ ConfigAction = config ,
115+ HandlerFactory = handlerFactory
116+ } ;
117+
118+ var state = this . typedClientOptions . TryAdd ( typeof ( TInterface ) , options ) ;
119+ if ( state == false )
120+ {
121+ throw new InvalidOperationException ( $ "接口{ typeof ( TInterface ) } 不能重复注册") ;
122+ }
55123 }
56124
57125 /// <summary>
58126 /// 创建实现了指定接口的HttpApiClient实例
59127 /// </summary>
60128 /// <typeparam name="TInterface"></typeparam>
61129 /// <returns></returns>
62- public TInterface CreateHttpApiClient < TInterface > ( ) where TInterface : class , IHttpApi
130+ public TInterface CreateTypedClient < TInterface > ( ) where TInterface : class , IHttpApi
63131 {
64132 var apiType = typeof ( TInterface ) ;
65133 var entry = this . activeEntries . GetOrAdd ( apiType , this . activeEntryFactory ) . Value ;
66134 return HttpApiClient . Create < TInterface > ( entry . HttpApiConfig ) ;
67135 }
68136
137+ /// <summary>
138+ /// 创建激活状态的Handler记录
139+ /// </summary>
140+ /// <param name="apiType">http接口类型</param>
141+ /// <returns></returns>
69142 private ActiveHandlerEntry CreateActiveEntry ( Type apiType )
70143 {
71- var handler = new LifeTimeTrackingHandler ( new DefaultHttpClientHandler ( ) ) ;
72- var httpApiConfig = new HttpApiConfig ( handler , false ) ;
73-
74- if ( this . configs . TryGetValue ( apiType , out Action < HttpApiConfig > config ) == false )
144+ if ( this . typedClientOptions . TryGetValue ( apiType , out var option ) == false )
75145 {
76146 throw new ArgumentException ( $ "未注册的接口类型{ apiType } ") ;
77147 }
78- else if ( config != null )
148+
149+ var innder = option . HandlerFactory . Invoke ( ) ;
150+ var handler = new LifeTimeTrackingHandler ( innder ) ;
151+ var httpApiConfig = new HttpApiConfig ( handler , false ) ;
152+
153+ if ( option . ConfigAction != null )
79154 {
80- config . Invoke ( httpApiConfig ) ;
155+ option . ConfigAction . Invoke ( httpApiConfig ) ;
81156 }
82157
83158 return new ActiveHandlerEntry ( this )
84159 {
85160 ApiType = apiType ,
86- HttpApiConfig = httpApiConfig ,
87- InnerHandler = handler . InnerHandler
161+ Disposable = innder ,
162+ HttpApiConfig = httpApiConfig
88163 } ;
89164 }
90165
166+ /// <summary>
167+ /// 当有记录失效时
168+ /// </summary>
169+ /// <param name="active">激活的记录</param>
91170 void IHttpApiClientFactory . OnEntryDeactivate ( ActiveHandlerEntry active )
92171 {
93172 this . activeEntries . TryRemove ( active . ApiType , out var _ ) ;
94173 var expired = new ExpiredHandlerEntry ( active ) ;
95174 this . expiredEntries . Enqueue ( expired ) ;
96175 }
97176
177+ /// <summary>
178+ /// 注册清理任务
179+ /// </summary>
98180 private void RegisteCleanup ( )
99181 {
100- Task . Delay ( this . defaultCleanupInterval )
182+ Task . Delay ( this . cleanupInterval )
101183 . ConfigureAwait ( false )
102184 . GetAwaiter ( )
103185 . OnCompleted ( this . CleanupCallback ) ;
104186 }
105187
188+ /// <summary>
189+ /// 清理任务回调
190+ /// </summary>
106191 private void CleanupCallback ( )
107192 {
108193 var count = this . expiredEntries . Count ;
109194 for ( var i = 0 ; i < count ; i ++ )
110195 {
111196 this . expiredEntries . TryDequeue ( out var entry ) ;
112- if ( entry . CanDispose ( ) == true )
197+ if ( entry . CanDispose == true )
113198 {
114199 entry . Dispose ( ) ;
115200 }
@@ -118,6 +203,8 @@ private void CleanupCallback()
118203 this . expiredEntries . Enqueue ( entry ) ;
119204 }
120205 }
206+
207+
121208 this . RegisteCleanup ( ) ;
122209 }
123210 }
0 commit comments