Skip to content

Commit d1a99e8

Browse files
committed
TimeoutAttribute支持修饰参数
1 parent 1956718 commit d1a99e8

File tree

6 files changed

+166
-89
lines changed

6 files changed

+166
-89
lines changed

WebApiClient.Test/Attributes/HttpActionAttributes/TimeoutAttributeTest.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading.Tasks;
4+
using WebApiClient;
5+
using WebApiClient.Attributes;
6+
using WebApiClient.Contexts;
7+
using Xunit;
8+
9+
10+
namespace WebApiClient.Test.Attributes
11+
{
12+
public class TimeoutAttributeTest
13+
{
14+
[Fact]
15+
public async Task BeforeRequestAsyncTest()
16+
{
17+
var context = new TestActionContext(
18+
httpApi: null,
19+
httpApiConfig: new HttpApiConfig(),
20+
apiActionDescriptor: new ApiActionDescriptor(typeof(IMyApi).GetMethod("PostAsync")));
21+
22+
var attr = new TimeoutAttribute(50);
23+
await attr.BeforeRequestAsync(context);
24+
25+
await Task.Delay(100);
26+
var canceled = context.CancellationTokens[0].IsCancellationRequested;
27+
Assert.True(canceled);
28+
}
29+
30+
[Fact]
31+
public async Task BeforeRequestAsync_ParameterTest()
32+
{
33+
var context = new TestActionContext(
34+
httpApi: null,
35+
httpApiConfig: new HttpApiConfig(),
36+
apiActionDescriptor: new ApiActionDescriptor(typeof(IMyApi).GetMethod("PostAsync")));
37+
38+
IApiParameterAttribute attr = new TimeoutAttribute(50);
39+
40+
var parameter = context.ApiActionDescriptor.Parameters[0].Clone(10);
41+
await attr.BeforeRequestAsync(context, parameter);
42+
43+
await Task.Delay(20);
44+
var canceled = context.CancellationTokens[0].IsCancellationRequested;
45+
Assert.True(canceled);
46+
47+
48+
parameter = context.ApiActionDescriptor.Parameters[0].Clone(TimeSpan.FromMilliseconds(5));
49+
await attr.BeforeRequestAsync(context, parameter);
50+
51+
await Task.Delay(10);
52+
canceled = context.CancellationTokens[0].IsCancellationRequested;
53+
Assert.True(canceled);
54+
}
55+
}
56+
}

WebApiClient/Attributes/FormFieldAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public override async Task BeforeRequestAsync(ApiActionContext context)
5959
{
6060
if (string.IsNullOrEmpty(this.name))
6161
{
62-
throw new NotSupportedException($"请传入name和value参数:{nameof(FormFieldAttribute)}");
62+
throw new HttpApiConfigException($"请传入name和value参数:{nameof(FormFieldAttribute)}");
6363
}
6464

6565
if (this.IsIgnoreWith(this.value) == false)

WebApiClient/Attributes/HttpActionAttributes/TimeoutAttribute.cs

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

WebApiClient/Attributes/MulitpartTextAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public override async Task BeforeRequestAsync(ApiActionContext context)
5959
{
6060
if (string.IsNullOrEmpty(this.name))
6161
{
62-
throw new NotSupportedException($"请传入name和value参数:{nameof(MulitpartTextAttribute)}");
62+
throw new HttpApiConfigException($"请传入name和value参数:{nameof(MulitpartTextAttribute)}");
6363
}
6464

6565
if (this.IsIgnoreWith(this.value) == false)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using WebApiClient.Contexts;
6+
7+
namespace WebApiClient.Attributes
8+
{
9+
/// <summary>
10+
/// 表示此请求的超时时间
11+
/// </summary>
12+
[DebuggerDisplay("Timeout = {TimeSpan}")]
13+
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
14+
public class TimeoutAttribute : ApiActionAttribute, IApiParameterAttribute
15+
{
16+
/// <summary>
17+
/// 获取超时时间
18+
/// </summary>
19+
public TimeSpan? TimeSpan { get; private set; }
20+
21+
/// <summary>
22+
/// 表示将参数值作为请求的超时时间
23+
/// </summary>
24+
public TimeoutAttribute()
25+
{
26+
}
27+
28+
/// <summary>
29+
/// 指定请求的超时时间
30+
/// </summary>
31+
/// <param name="milliseconds">超时时间的毫秒数</param>
32+
public TimeoutAttribute(int milliseconds)
33+
: this((double)milliseconds)
34+
{
35+
}
36+
37+
/// <summary>
38+
/// 指定请求的超时时间
39+
/// </summary>
40+
/// <param name="milliseconds">超时时间的毫秒数</param>
41+
public TimeoutAttribute(double milliseconds)
42+
{
43+
this.TimeSpan = System.TimeSpan.FromMilliseconds(milliseconds);
44+
}
45+
46+
/// <summary>
47+
/// 执行前
48+
/// </summary>
49+
/// <param name="context">上下文</param>
50+
/// <exception cref="HttpApiConfigException"></exception>
51+
/// <returns></returns>
52+
public override Task BeforeRequestAsync(ApiActionContext context)
53+
{
54+
if (this.TimeSpan.HasValue == false)
55+
{
56+
throw new HttpApiConfigException($"请传入milliseconds参数:{nameof(TimeoutAttribute)}");
57+
}
58+
59+
this.SetTimeout(context, this.TimeSpan.Value);
60+
return ApiTask.CompletedTask;
61+
}
62+
63+
/// <summary>
64+
/// http请求之前
65+
/// </summary>
66+
/// <param name="context">上下文</param>
67+
/// <param name="parameter">特性关联的参数</param>
68+
/// <exception cref="HttpApiConfigException"></exception>
69+
/// <returns></returns>
70+
Task IApiParameterAttribute.BeforeRequestAsync(ApiActionContext context, ApiParameterDescriptor parameter)
71+
{
72+
if (parameter.Value is IConvertible convertible)
73+
{
74+
var doubleValue = Convert.ToDouble(convertible);
75+
var timeout = System.TimeSpan.FromMilliseconds(doubleValue);
76+
this.SetTimeout(context, timeout);
77+
}
78+
else if (parameter.Value is TimeSpan timeout)
79+
{
80+
this.SetTimeout(context, timeout);
81+
}
82+
else
83+
{
84+
throw new HttpApiConfigException($"无法将参数{parameter.Member}转换为Timeout");
85+
}
86+
return ApiTask.CompletedTask;
87+
}
88+
89+
90+
/// <summary>
91+
/// 设置超时时间到上下文
92+
/// </summary>
93+
/// <param name="context">上下文</param>
94+
/// <param name="timeout">超时时间</param>
95+
/// <exception cref="HttpApiConfigException"></exception>
96+
private void SetTimeout(ApiActionContext context, TimeSpan timeout)
97+
{
98+
var maxTimeout = context.HttpApiConfig.HttpClient.Timeout;
99+
if (maxTimeout >= System.TimeSpan.Zero && timeout > maxTimeout)
100+
{
101+
throw new HttpApiConfigException($"Timeout值{timeout}不能超时HttpApiConfig.HttpClient.Timeout");
102+
}
103+
104+
var cancellation = new CancellationTokenSource(timeout);
105+
context.CancellationTokens.Add(cancellation.Token);
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)