问题描述
一段时间以来,我一直在通过AJAX调用使用服务栈,但没有出现问题,但是最近创建了一个利用服务栈客户端(特别是JsonServiceClient)的winforms快速应用程序.
I have been using service stack via AJAX calls for some time without issue, but have recently created a quick winforms app which utilizes the service stack client (specifically JsonServiceClient).
但是-我遇到了一个问题,即我在呼叫中始终遇到超时,该呼叫在前两次尝试中均成功运行.看起来服务堆栈客户端正在保留某些资源,或者我使用的客户端方法有误.它仅在针对远程服务运行时才会发生(每次都在本地计算机上运行).这是我的代码,但例外:
However - I have hit a problem whereby I consistently get a timeout on a call which works successfully on the the first TWO attempts. It looks like either the service stack client is holding on to some resource, or I am using the client in the wrong way. It only occurs when running against a remote service (works every time on a local machine). Here is my code, and the exception:
var url = "http://www.TestServer.com/api";
var taskId = Guid.Parse("30fed418-214b-e411-80c1-22000a5b9fe5");
var email = "[email protected]";
using (var client = new JsonServiceClient(url))
{
var result = client.Send(new Authenticate {UserName = "username", Password = "Password01", RememberMe = true});
client.Put(new AssignTask { AdminTaskId = taskId, Assignee = email });//Call #1 - works fine
client.Put(new AssignTask { AdminTaskId = taskId, Assignee = email });//Call #2 - works fine
try
{
client.Put(new AssignTask { AdminTaskId = taskId, Assignee = email });//Call #3 - works fine
}
catch (WebException ex)
{
//Times out every time
//at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
//at System.Net.HttpWebRequest.GetRequestStream()
//at ServiceStack.Net40PclExport.GetRequestStream(WebRequest webRequest)
//at ServiceStack.ServiceClientBase.<>c__DisplayClassa.<SendRequest>b__9(HttpWebRequest client)
//at ServiceStack.ServiceClientBase.PrepareWebRequest(String httpMethod, String requestUri, Object request, Action`1 sendRequestAction)
//at ServiceStack.ServiceClientBase.SendRequest(String httpMethod, String requestUri, Object request)
//at ServiceStack.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request)
//at ServiceStack.ServiceClientBase.Put[TResponse](String relativeOrAbsoluteUrl, Object requestDto)
//at ServiceStack.ServiceClientBase.Put(Object requestDto)
//at SSClientIssue.Program.Main(String[] args) in c:\Users\David\Documents\Visual Studio 2013\Projects\SSClientIssue\SSClientIssue\Program.cs:line 27
throw;
}
}
超时后,我可以关闭并重新加载应用程序(服务器保持运行状态),然后再次得到相同的行为(两次成功调用). IIS日志显示,第3次调用没有到达服务器,因此看起来像是客户端问题.
After the timeout, I can close and reload the app (server stays up), and then get same behavior again (two successful calls). IIS logs show that the 3rd call does not make it to the server, so looks like a Client issue.
我已经看了8个小时了,我想我的眼睛开始流血...如果有人可以帮我,我会给你买啤酒!
I have been looking at this for 8 hours and I think my eyes are starting to bleed...If anyone can help I will buy you a beer!
推荐答案
问题是由于您的ServiceClient
请求未指定已知的响应类型而导致的.
The issue is due to your ServiceClient
requests not specifying a known response type.
可以使用IReturn<T>
标记(推荐)在请求DTO"上标记响应类型:
Response types can either be marked on the Request DTO using the IReturn<T>
marker (recommended):
public class GetAllAdminUsernamesRequest : IReturn<List<string>> { ... }
通过在Request DTO上添加此内容,ServiceClient能够自动推断和转换响应,例如:
By adding this on the Request DTO, the ServiceClient is able to automatically infer and convert the response, e.g:
List<string> response = client.Get(new GetCurrentAdminUserAdminTasks());
否则,在请求DTO上指定响应的另一种方法是在呼叫站点上指定它,例如:
Otherwise an alternative to specifying the Response on the Request DTO, is to specify it on the call-site, e.g:
List<string> response = client.Get<List<string>>(new GetCurrentAdminUserAdminTasks());
如果不执行此操作,则响应是未知的,因此ServiceClient将仅返回基础HttpWebResponse
,以便您可以自己检查响应.
If you don't do this the Response is unknown so the ServiceClient will just return the underlying HttpWebResponse
so you can inspect the response yourself.
HttpWebResponse tasks = client.Get(new GetCurrentAdminUserAdminTasks());
为了能够检查和读取HttpWebResponse
,响应不能由ServiceClient处理,因此,由呼叫站点提出请求以正确处理该请求,即:
In order to be able to inspect and read from the HttpWebResponse
the response cannot be disposed by the ServiceClient, so it's up to the call-site making the request to properly dispose of it, i.e:
using (HttpWebResponse tasks = client.Get(new GetCurrentAdminUserAdminTasks())) {}
using (HttpWebResponse adminUsers = client.Get(new GetAllAdminUsernames())) {}
try
{
using (client.Put(new AssignTask { AdminTaskId = taskId, Assignee = user })) {}
using (client.Put(new AssignTask { AdminTaskId = taskId, Assignee = user })) {}
using (client.Put(new AssignTask { AdminTaskId = taskId, Assignee = user })) {}
using (client.Put(new AssignTask { AdminTaskId = taskId, Assignee = user })) {}
}
...
处理WebResponses响应将解决您的问题.
Disposing of your WebResponses responses will resolve your issue.
如果不这样做,则基础WebRequest
会限制打开的连接,并且一次只能允许有限数量的同时连接通过,这可能是防止DDOS攻击的安全措施.这就是使基础连接保持打开状态并WebRequest
处于阻塞状态,等待它们释放的原因.
If you don't do this the underlying WebRequest
will throttle open connections and only let a limited number of simultaneous connections through at any one time, possibly as a safe-guard to prevent DDOS attacks. This is what keeps the underlying connections open and WebRequest
to block, waiting for them to be released.
这篇关于使用ServiceStack.Client超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!