Skip to content

Commit 647546f

Browse files
committed
IHttpApiFactory改为泛型
1 parent cbd8db9 commit 647546f

File tree

6 files changed

+122
-118
lines changed

6 files changed

+122
-118
lines changed

WebApiClient.Test/HttpApiFactoryTest.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,21 @@
99
namespace WebApiClient.Test
1010
{
1111
public class HttpApiFactoryTest
12-
{
13-
[Fact]
14-
public void AddHttpApiTest()
15-
{
16-
var factory = new HttpApiFactory();
17-
factory.AddHttpApi<IMyApi>(null, null);
18-
19-
Assert.Throws<InvalidOperationException>(() => factory.AddHttpApi<IMyApi>(null, null));
20-
}
12+
{
2113

2214
[Fact]
2315
public void CreateHttpApiTest()
2416
{
25-
var factory = new HttpApiFactory { Lifetime = TimeSpan.FromMilliseconds(100) };
26-
factory.AddHttpApi<IMyApi>(null, null);
27-
28-
var api1 = factory.CreateHttpApi<IMyApi>();
29-
var api2 = factory.CreateHttpApi<IMyApi>();
17+
var factory = new HttpApiFactory <IMyApi>(null, null) { Lifetime = TimeSpan.FromMilliseconds(100) };
18+
19+
var api1 = factory.CreateHttpApi();
20+
var api2 = factory.CreateHttpApi();
3021
Assert.True(IsHttpApiConfigEquals(api1, api2));
3122
Assert.False(api1 == api2);
3223

3324
Thread.Sleep(TimeSpan.FromMilliseconds(150));
3425

35-
var api3 = factory.CreateHttpApi<IMyApi>();
26+
var api3 = factory.CreateHttpApi();
3627
Assert.False(IsHttpApiConfigEquals(api1, api3));
3728
}
3829

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,90 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Net.Http;
34

45
namespace WebApiClient
56
{
67
/// <summary>
7-
/// 表示HttpApi创建工厂
8+
/// 表示HttpApi创建工厂表示操作
89
/// 提供HttpApi的配置注册和实例创建
910
/// 并对实例的生命周期进行自动管理
1011
/// </summary>
11-
public partial class HttpApiFactory
12+
public static class HttpApiFactory
1213
{
1314
/// <summary>
14-
/// 获取默认工厂实例
15+
/// 同步锁
1516
/// </summary>
16-
public static readonly HttpApiFactory Default = new HttpApiFactory();
17+
private static object syncRoot = new object();
1718

1819
/// <summary>
19-
/// 注册http接口到默认工厂
20+
/// 工厂字典
21+
/// </summary>
22+
private static readonly ConcurrentDictionary<Type, IHttpApiFactory> factories;
23+
24+
/// <summary>
25+
/// 表示HttpApi创建工厂
26+
/// </summary>
27+
static HttpApiFactory()
28+
{
29+
factories = new ConcurrentDictionary<Type, IHttpApiFactory>();
30+
}
31+
32+
/// <summary>
33+
/// 注册http接口
2034
/// </summary>
2135
/// <typeparam name="TInterface"></typeparam>
2236
/// <returns></returns>
2337
public static bool Add<TInterface>() where TInterface : class, IHttpApi
2438
{
25-
return Add<TInterface>(config: null);
39+
return Add<TInterface>(configAction: null);
2640
}
2741

2842
/// <summary>
29-
/// 注册http接口到默认工厂
43+
/// 注册http接口
3044
/// </summary>
3145
/// <typeparam name="TInterface"></typeparam>
32-
/// <param name="config">HttpApiConfig的配置</param>
46+
/// <param name="configAction">HttpApiConfig的配置委托</param>
3347
/// <returns></returns>
34-
public static bool Add<TInterface>(Action<HttpApiConfig> config) where TInterface : class, IHttpApi
48+
public static bool Add<TInterface>(Action<HttpApiConfig> configAction) where TInterface : class, IHttpApi
3549
{
36-
return Add<TInterface>(config, handlerFactory: null);
50+
return Add<TInterface>(configAction, handlerFunc: null);
3751
}
3852

3953
/// <summary>
40-
/// 注册http接口到默认工厂
54+
/// 注册http接口
4155
/// </summary>
4256
/// <typeparam name="TInterface"></typeparam>
43-
/// <param name="config">HttpApiConfig的配置</param>
44-
/// <param name="handlerFactory">HttpMessageHandler创建委托</param>
57+
/// <param name="configAction">HttpApiConfig的配置</param>
58+
/// <param name="handlerFunc">HttpMessageHandler创建委托</param>
4559
/// <returns></returns>
46-
public static bool Add<TInterface>(Action<HttpApiConfig> config, Func<HttpMessageHandler> handlerFactory) where TInterface : class, IHttpApi
60+
public static bool Add<TInterface>(Action<HttpApiConfig> configAction, Func<HttpMessageHandler> handlerFunc) where TInterface : class, IHttpApi
4761
{
48-
return Default.AddHttpApi<TInterface>(config, handlerFactory);
62+
lock (syncRoot)
63+
{
64+
var apiType = typeof(TInterface);
65+
if (factories.ContainsKey(apiType) == true)
66+
{
67+
return false;
68+
}
69+
70+
var factory = new HttpApiFactory<TInterface>(configAction, handlerFunc);
71+
return factories.TryAdd(apiType, factory);
72+
}
4973
}
5074

5175
/// <summary>
52-
/// 使用默认工厂创建指定接口的代理实例
76+
/// 创建指定接口的代理实例
5377
/// </summary>
5478
/// <typeparam name="TInterface"></typeparam>
55-
/// <exception cref="ArgumentException"></exception>
79+
/// <exception cref="InvalidOperationException"></exception>
5680
/// <returns></returns>
5781
public static TInterface Create<TInterface>() where TInterface : class, IHttpApi
5882
{
59-
return Default.CreateHttpApi<TInterface>();
83+
if (factories.TryGetValue(typeof(TInterface), out var factory) == true)
84+
{
85+
return factory.CreateHttpApi() as TInterface;
86+
}
87+
throw new InvalidOperationException($"未注册的接口类型:{typeof(TInterface)}");
6088
}
6189
}
6290
}

WebApiClient/HttpApiFactory.cs

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,39 @@ namespace WebApiClient
1111
/// 提供HttpApi的配置注册和实例创建
1212
/// 并对实例的生命周期进行自动管理
1313
/// </summary>
14-
public partial class HttpApiFactory : IHttpApiFactory, _IHttpApiFactory
14+
public class HttpApiFactory<TInterface> : IHttpApiFactory<TInterface>, IHttpApiFactory, _IHttpApiFactory
15+
where TInterface : class, IHttpApi
1516
{
1617
/// <summary>
17-
/// handler的生命周期
18+
/// HttpApiConfig的配置委托
1819
/// </summary>
19-
private TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
20+
private readonly Action<HttpApiConfig> configAction;
2021

2122
/// <summary>
22-
/// 清理handler时间间隔
23+
/// HttpMessageHandler的创建委托
2324
/// </summary>
24-
private TimeSpan cleanupInterval = TimeSpan.FromSeconds(10d);
25+
private readonly Func<HttpMessageHandler> handlerFunc;
2526

2627
/// <summary>
27-
/// 过期的记录
28+
/// handler的生命周期
2829
/// </summary>
29-
private readonly ConcurrentQueue<ExpiredEntry> expiredEntries;
30+
private TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
3031

3132
/// <summary>
32-
/// 激活记录的创建工厂
33+
/// 清理handler时间间隔
3334
/// </summary>
34-
private readonly Func<Type, Lazy<ActiveEntry>> activeEntryFactory;
35+
private TimeSpan cleanupInterval = TimeSpan.FromSeconds(10d);
3536

3637
/// <summary>
37-
/// http接口代理创建选项
38+
/// 激活的记录
3839
/// </summary>
39-
private readonly ConcurrentDictionary<Type, HttpApiCreateOption> httpApiCreateOptions;
40+
private volatile Lazy<ActiveEntry> activeEntryLazy;
4041

4142
/// <summary>
42-
/// 激活的记录
43+
/// 过期的记录
4344
/// </summary>
44-
private readonly ConcurrentDictionary<Type, Lazy<ActiveEntry>> activeEntries;
45+
private readonly ConcurrentQueue<ExpiredEntry> expiredEntries;
46+
4547

4648
/// <summary>
4749
/// 获取已过期但还未释放的HttpApi实例数量
@@ -95,78 +97,72 @@ public TimeSpan CleanupInterval
9597
/// HttpApi创建工厂
9698
/// </summary>
9799
public HttpApiFactory()
100+
: this(configAction: null)
98101
{
102+
}
103+
104+
/// <summary>
105+
/// HttpApi创建工厂
106+
/// </summary>
107+
/// <param name="configAction">HttpApiConfig的配置委托</param>
108+
public HttpApiFactory(Action<HttpApiConfig> configAction)
109+
: this(configAction, handlerFunc: null)
110+
{
111+
}
112+
113+
/// <summary>
114+
/// HttpApi创建工厂
115+
/// </summary>
116+
/// <param name="configAction">HttpApiConfig的配置委托</param>
117+
/// <param name="handlerFunc">HttpMessageHandler的创建委托</param>
118+
public HttpApiFactory(Action<HttpApiConfig> configAction, Func<HttpMessageHandler> handlerFunc)
119+
{
120+
this.configAction = configAction;
121+
this.handlerFunc = handlerFunc ?? new Func<HttpMessageHandler>(() => new DefaultHttpClientHandler());
122+
99123
this.expiredEntries = new ConcurrentQueue<ExpiredEntry>();
100-
this.activeEntries = new ConcurrentDictionary<Type, Lazy<ActiveEntry>>();
101-
this.httpApiCreateOptions = new ConcurrentDictionary<Type, HttpApiCreateOption>();
102-
this.activeEntryFactory = apiType => new Lazy<ActiveEntry>(() => this.CreateActiveEntry(apiType), LazyThreadSafetyMode.ExecutionAndPublication);
124+
this.activeEntryLazy = new Lazy<ActiveEntry>(this.CreateActiveEntry, LazyThreadSafetyMode.ExecutionAndPublication);
103125

104126
this.RegisteCleanup();
105127
}
106128

107129
/// <summary>
108-
/// 注册http接口
130+
/// 创建接口的代理实例
109131
/// </summary>
110-
/// <typeparam name="TInterface"></typeparam>
111-
/// <param name="config">HttpApiConfig的配置</param>
112-
/// <param name="handlerFactory">HttpMessageHandler创建委托</param>
113132
/// <returns></returns>
114-
public bool AddHttpApi<TInterface>(Action<HttpApiConfig> config, Func<HttpMessageHandler> handlerFactory) where TInterface : class, IHttpApi
133+
public TInterface CreateHttpApi()
115134
{
116-
if (handlerFactory == null)
117-
{
118-
handlerFactory = () => new DefaultHttpClientHandler();
119-
}
120-
121-
var options = new HttpApiCreateOption
122-
{
123-
ConfigAction = config,
124-
HandlerFactory = handlerFactory
125-
};
126-
127-
return this.httpApiCreateOptions.TryAdd(typeof(TInterface), options);
135+
return ((IHttpApiFactory)this).CreateHttpApi() as TInterface;
128136
}
129137

130138
/// <summary>
131-
/// 创建指定接口的代理实例
139+
/// 创建接口的代理实例
132140
/// </summary>
133-
/// <typeparam name="TInterface"></typeparam>
134-
/// <exception cref="ArgumentException"></exception>
135141
/// <returns></returns>
136-
public TInterface CreateHttpApi<TInterface>() where TInterface : class, IHttpApi
142+
object IHttpApiFactory.CreateHttpApi()
137143
{
138-
var apiType = typeof(TInterface);
139-
var entry = this.activeEntries.GetOrAdd(apiType, this.activeEntryFactory).Value;
140-
return HttpApiClient.Create(apiType, entry.Interceptor) as TInterface;
144+
var interceptor = this.activeEntryLazy.Value.Interceptor;
145+
return HttpApiClient.Create(typeof(TInterface), interceptor);
141146
}
142147

143148
/// <summary>
144149
/// 创建激活状态的记录
145150
/// </summary>
146-
/// <param name="apiType">http接口类型</param>
147-
/// <exception cref="ArgumentException"></exception>
148151
/// <returns></returns>
149-
private ActiveEntry CreateActiveEntry(Type apiType)
152+
private ActiveEntry CreateActiveEntry()
150153
{
151-
if (this.httpApiCreateOptions.TryGetValue(apiType, out var option) == false)
152-
{
153-
throw new ArgumentException($"未注册的接口类型{apiType}");
154-
}
155-
156-
var handler = option.HandlerFactory.Invoke();
157-
var httpApiConfig = new HttpApiConfig(handler, false);
154+
var httpApiConfig = new HttpApiConfig(this.handlerFunc.Invoke(), true);
158155
var interceptor = new LifeTimeTrackingInterceptor(httpApiConfig);
159156

160-
if (option.ConfigAction != null)
157+
if (this.configAction != null)
161158
{
162-
option.ConfigAction.Invoke(httpApiConfig);
159+
this.configAction.Invoke(httpApiConfig);
163160
}
164161

165162
return new ActiveEntry(this)
166163
{
167-
ApiType = apiType,
168-
Disposable = httpApiConfig,
169-
Interceptor = interceptor
164+
Interceptor = interceptor,
165+
Disposable = httpApiConfig
170166
};
171167
}
172168

@@ -176,7 +172,9 @@ private ActiveEntry CreateActiveEntry(Type apiType)
176172
/// <param name="active">激活的记录</param>
177173
void _IHttpApiFactory.OnEntryDeactivate(ActiveEntry active)
178174
{
179-
this.activeEntries.TryRemove(active.ApiType, out var _);
175+
// 切换激活状态的记录的实例
176+
this.activeEntryLazy = new Lazy<ActiveEntry>(this.CreateActiveEntry, LazyThreadSafetyMode.ExecutionAndPublication);
177+
180178
var expired = new ExpiredEntry(active);
181179
this.expiredEntries.Enqueue(expired);
182180
}
@@ -214,5 +212,6 @@ private void CleanupCallback()
214212

215213
this.RegisteCleanup();
216214
}
215+
217216
}
218217
}

WebApiClient/IHttpApiFactory.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,22 @@
66
public interface IHttpApiFactory
77
{
88
/// <summary>
9-
/// 创建指定接口的代理实例
9+
/// 创建接口的代理实例
1010
/// </summary>
11-
/// <typeparam name="TInterface"></typeparam>
1211
/// <returns></returns>
13-
TInterface CreateHttpApi<TInterface>() where TInterface : class, IHttpApi;
12+
object CreateHttpApi();
13+
}
14+
15+
/// <summary>
16+
/// 定义HttpApi工厂的接口
17+
/// </summary>
18+
/// <typeparam name="TInterface"></typeparam>
19+
public interface IHttpApiFactory<TInterface> : IHttpApiFactory where TInterface : class, IHttpApi
20+
{
21+
/// <summary>
22+
/// 创建接口的代理实例
23+
/// </summary>
24+
/// <returns></returns>
25+
new TInterface CreateHttpApi();
1426
}
1527
}

WebApiClient/Internal/HttpApiFactories/ActiveEntry.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ namespace WebApiClient
88
/// </summary>
99
class ActiveEntry
1010
{
11-
/// <summary>
12-
/// 获取或设置关联的http接口类型
13-
/// </summary>
14-
public Type ApiType { get; set; }
15-
1611
/// <summary>
1712
/// 获取或设置用于释放资源的对象
1813
/// </summary>

WebApiClient/Internal/HttpApiFactories/HttpApiCreateOption.cs

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)