【发布时间】:2018-10-12 09:09:32
【问题描述】:
我在致电api/Values/Test?times={x} 时遇到以下问题。 x 为 1、2、...时不会出现此问题,但在达到 9、10 等时 Web 请求会超时。
如您所见,Test 端点将向EndPointx 发出网络请求次(请原谅无意义的方法体,它们在实践中会做更有意义的事情):
public class ValuesController: System.Web.Http.ApiController
{
[HttpGet]
public async Task<object> Test(int times)
{
var tasks = new List<Task<int>>();
for (var i = 0; i < times; i++)
{
//Make web request to the `EndPoint` method below
var task = new ApiRequestBuilder<int>("https://localhost:44301/api/Values/EndPoint")
.GetAsync();
tasks.Add(task);
}
return await Task.WhenAll(tasks.ToArray());
}
[HttpGet]
[CustomAuthorise]//This makes a web request to `AuthEndPoint` (below)
public int EndPoint()
{
return 0;
}
[HttpGet]
public bool AuthEndPoint()
{
return true;
}
}
(NB见下文ApiRequestBuilder是什么)
然而,问题不是 EndPoint 被击中 x 次,而是 CustomAuthorise 属性发出进一步的网络请求,这就是问题所在:
public class CustomAuthoriseAttribute : System.Web.Http.AuthorizeAttribute
{
public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
var result = await this.AuthoriseAsync(actionContext);
if (!result)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
}
}
public virtual async Task<bool> AuthoriseAsync(HttpActionContext context)
{
//***********HANGING HERE************
//var result= await new ApiRequestBuilder<bool>("https://www.example.com")
var result= await new ApiRequestBuilder<bool>("https://localhost:44301/Values/AuthEndPoint")
.GetAsync();
return result;
}
}
如您所见,我已将路线 "https://www.example.com" 注释掉。当我将 url 设置为不是 localhost 的内容时,无论我想要多少,都可以向该网络请求发送垃圾邮件(通过将 x 设置为一个大数字)。
ApiRequestBuilder 是通过System.Net.Http.HttpClient(版本4.0.0.0,.NETframework v4.5.1)发出Web 请求的助手,它将响应序列化为您提供给它的泛型类型参数。
public class ApiRequestBuilder<T>
{
protected string Url => Uri?.AbsoluteUri;
protected Uri Uri;
protected readonly HttpClient Client;
public ApiRequestBuilder(string url)
{
Uri = new Uri(url);
var client = new HttpClient()
{
BaseAddress = this.Uri,
//Set timeout so replicating this issue itn't a pain
Timeout = TimeSpan.FromSeconds(5)
};
this.Client = client;
}
public async Task<T> GetAsync()
{
var response = await this.Client.GetAsync(this.Url);
var responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseContent);
}
}
我尝试过的事情:
在
ApiRequestBuilder中每次使用HttpClient都有一个using语句 - 仍然挂起。在
ValuesController.Test的 for 循环中等待每个Task- 这可行,但不能解决我的问题,因为实际上我正在尝试模拟并发性以使用我的自定义身份验证属性。
可能有用:
我在端口
44301上运行本地 IIS,最大并发连接数很大 - 4294967295。就像我说的,在授权时将 url 从
localhost更改为example.com可以解决问题,从而将问题隔离为我的本地设置有问题
有谁知道为什么在授权属性中使用 Web 请求似乎与使用 localhost 的并发性有关,而不是在广阔的世界中使用 url?
更新
在挂起时运行netstat -n(我为此删除了超时,以便查看 TCP 连接在做什么)。对于看似被阻止的每个正在进行的网络请求,我都有以下内容:
Proto Local Address Foreign Address State
TCP [::1]:44301 [::1]:44728 CLOSE_WAIT
TCP [::1]:44728 [::1]:44301 FIN_WAIT_2
在this 的帮助下,似乎服务器已要求客户端退出,客户端已确认,但它们都挂起(客户端没有关闭?)。
【问题讨论】:
标签: asp.net asp.net-web-api2 authorization dotnet-httpclient