使用ServiceStack.Client超时

时间:2014-10-21 09:32:43

标签: httpwebrequest servicestack webmethod

我一直在通过AJAX调用使用服务堆栈一段时间没有问题,但最近创建了一个使用服务堆栈客户端(特别是JsonServiceClient)的快速winforms应用程序。

但是 - 我遇到了一个问题,即我一直在通话中超时,这在前两次尝试中成功运行。它看起来像服务堆栈客户端持有某些资源,或者我以错误的方式使用客户端。它仅在针对远程服务运行时发生(每次在本地计算机上运行)。这是我的代码,例外:

        var url = "http://www.TestServer.com/api";
        var taskId = Guid.Parse("30fed418-214b-e411-80c1-22000a5b9fe5");
        var email = "admin@example.com";

        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次调用未进入服务器,因此看起来像是客户端问题。

我一直在看这个8个小时,我觉得我的眼睛开始流血......如果有人可以帮我,我会给你买啤酒!

1 个答案:

答案 0 :(得分:7)

问题是由于您的ServiceClient请求未指定已知的响应类型。

可以使用IReturn<T>标记(推荐)在Request DTO上标记响应类型:

public class GetAllAdminUsernamesRequest : IReturn<List<string>> { ... }

通过在Request DTO上添加此功能,ServiceClient能够自动推断并转换响应,例如:

List<string> response = client.Get(new GetCurrentAdminUserAdminTasks());

否则,在请求DTO上指定响应的替代方法是在呼叫站点上指定它,例如:

List<string> response = client.Get<List<string>>(new GetCurrentAdminUserAdminTasks());

如果您不这样做,则响应未知,因此ServiceClient将返回基础HttpWebResponse,以便您自己检查响应。

HttpWebResponse tasks = client.Get(new GetCurrentAdminUserAdminTasks());

为了能够检查和读取HttpWebResponse,ServiceClient无法处理响应,因此由呼叫站点提出正确处理它的请求,即:

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回复将解决您的问题。

如果不这样做,基础WebRequest将限制打开的连接,并且在任何时候只允许有限数量的同时连接通过,可能作为防止DDOS攻击的安全防护。这就是保持底层连接打开并阻止WebRequest阻止等待它们被释放的原因。