2012-06-01 61 views
3

我有一个调用另一个REST服务的REST服务。两者都使用MVC 4 WebAPI,并称它们工作正常,直到我把它放在负载下。简化的代码是这样的:使用WebAPI/MVC从REST服务调用REST服务4

public HttpResponseMessage Get() 
{ 
    var url = WebHelpers.CreateUrl(Request, "EmployeesGet"); 
    var client = new HttpClient(); 
    var response = client.GetAsync(url).Result; 
    var retResp = new HttpResponseMessage(); 
    retResp.Content = response.Content; 
    return retResp; 
} 

WebHelper.CreateUrl构造端点URL。 当我穿上,100个用户模拟负载,我得到约16000请求,我得到一个插座异常:

SocketException由于系统缺乏足够的缓冲区空间或者因为无法执行套接字上的操作一个队列已满

这需要我的电脑的网络堆栈,直到我重置IIS。 我想也许我需要更积极的清理,所以我处置HttpClient没有任何效果。然后我想我需要处理从端点获得的响应,因为一旦我获得了内容,我就不再需要它了。奇怪的是,我然后得到一个异常,说一个处置对象不能被引用。这是来自MVC框架。异常如下:

[ObjectDisposedException:无法访问处置的对象。 对象名:' System.Net.Http.StreamContent '] System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult的结果)49019 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute(。 )469 System.Web.HttpApplication.ExecuteStep(IExecutionStep一步,布尔& completedSynchronously)+375

如果我回到流或仅仅是内容的东西做工精细,但我不能改变响应状态编码或添加任何其他元数据到响应。

那么从Get方法返回响应的最佳方式是从另一个REST服务调用中接收内容。我不想反序列化/序列化,我真的希望能够将一些数据添加到响应中。

更新:在进行负载测试时查看资源监视器时,发现连接堆叠在一起。看起来,我不能肯定地说,但看起来从Get()内部呼叫端点不是释放连接。

回答

2

我会建议尝试向控制器注入一个预先创建的HttpClient实例并跨请求重新使用它。当处理HttpClient时,它将关闭并尝试关闭底层连接。从我回想起的HttpClient源代码中,您将在每次创建新的HttpClient实例时打开一个新连接。

+0

我想到了。我可以试试。问题是每次调用的URL可能不同,每个客户端都有一个特定的站点实例。我会尝试一下,看看它是否有所作为。 – JayGlynn

+0

@JayGlynn如果url不同,应该不会有问题。 HttpClient被构建为被多个线程重复使用以进行同时呼叫。 –

+0

这有帮助,但我不得不每个线程使用一个实例(使用Ninject)。我改变了短暂端口的限制,这也造成了很大的不同。由于我正在提出另一个请求,因此我使用端口的速度是通常的两倍。 – JayGlynn

1

几件事情

  1. 要调用.Result将阻塞线程。这可能是你的性能问题的一部分。由于您正在执行异步操作,因此您应该通过返回Task<HttpResponseMessage>使您的操作方法变为异步,并计划将内部服务调用的结果转换为外部调用正文的延续。
  2. 我不确定将内部呼叫的HttpContent复制到外部呼叫的结果中。您可能想要尝试读取内部流并将其复制到新的外部流中。
+0

我知道我阻止了,但对端点的呼叫通常非常快,这不是问题。除此之外,我还会有一个开发团队在这个代码中工作,我想保持简单。返回一个Task或者一个流程,但是我没有权限访问添加元数据的响应。我们有一个自定义标题,我希望能够管理状态码。我想知道复制内容的好处,内容返回正常,所以它似乎正在工作,但有些东西不释放套接字资源。 – JayGlynn