致电api/Values/Test?times={x}
时遇到以下问题。当x
为1、2,...时不会发生此问题,但是Web请求达到9、10等时将超时。
如您所见,Test
端点将向EndPoint
x
次发出Web请求(无意义的方法体,它们在实践中将做更多有意义的事情):
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
属性,它发出了另一个Web请求,这就是问题所在:
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"
。当我将网址设置为非localhost
时,无论我想要多少垃圾邮件都会对该Web请求发出垃圾邮件(通过将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);
}
}
我尝试过的事情:
在using
中每次使用HttpClient
都有一个ApiRequestBuilder
语句-仍然挂起。
等待Task
的for循环中的每个ValuesController.Test
-可行,但不能解决我的问题,因为在实践中,我正在尝试使用自定义auth属性模拟并发
可能有用:
我在端口44301
上运行本地IIS,最大并发连接数量巨大-4294967295。
就像我说的那样,在授权时将网址从localhost
更改为example.com
之类的问题即可解决,将问题隔离到本地设置有问题
有人知道为什么在授权属性中使用Web请求似乎与localhost
并发而不是在广阔的世界中使用URL并发吗?
更新
在挂起时运行netstat -n
(我删除了超时,因此可以查看TCP连接的工作)。对于似乎被阻止的每个正在进行的Web请求,我都有以下内容:
Proto Local Address Foreign Address State
TCP [::1]:44301 [::1]:44728 CLOSE_WAIT
TCP [::1]:44728 [::1]:44301 FIN_WAIT_2
在this的帮助下,服务器似乎要求客户退出,客户承认了这一点,但是它们都挂了(客户端没有关闭吗?)。
答案 0 :(得分:0)
可能是因为创建了太多客户端,并导致套接字耗尽的已知问题。
引用YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE
使用单个静态客户端可能会解决此问题
class A
@@values = {}
def initialize
@@values.each{ |key, val|
puts("Key: #{key}, Val: #{val}")
}
end
end
class B < A
@@values = { "Test1" => "1", "Test2" => "2"}
def initialize
super
end
end
B.new
#⇒ Key: Test1, Val: 1
# Key: Test2, Val: 2
答案 1 :(得分:0)