【问题标题】:Timeout using ServiceStack.Client使用 ServiceStack.Client 超时
【发布时间】:2014-10-21 09:32:43
【问题描述】:

我通过 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 日志显示第三次调用没有到达服务器,因此看起来像是客户端问题。

我已经看了 8 个小时了,我觉得我的眼睛开始流血了……如果有人能帮忙,我会请你喝啤酒!

【问题讨论】:

  • 复制这个的最好方法是什么?您可以在 GitHub 复制中添加一个自包含示例或链接到我们可以在本地运行的 .zip 吗?
  • 对不起神话 - 带着一个新宝宝离开了!我已将 repro 添加到 GitHub (github.com/hiblen/SSIssue)。需要注意的一件事是,仅当客户端和服务位于不同的机器上时才会出现问题(在我的情况下,通过互联网针对 AWS 实例)。我怀疑这是因为 Windows 中的连接限制......我可能错了。客户端代码显示引发错误的位置。如果您需要更多详细信息,请大声喊叫......很乐意解决这个问题。

标签: httpwebrequest servicestack webmethod


【解决方案1】:

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

可以使用 IReturn&lt;T&gt; 标记在请求 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 等待它们被释放的原因。

【讨论】:

  • 如何处理异步请求?我在从 PostAsync 返回的 Task 上使用 Success 和 Error 回调(通过扩展方法)。我会在回调中调用 WebResponse 上的 Dispose 吗?
  • @mythz 我和 AndyMoose 有同样的问题,即使我的响应是在请求 DTO 和 Xamarin.iOS 客户端中输入的,我也遇到了服务超时间歇性问题。我正在使用成功和错误回调那么在这种情况下我们需要做一些特别的事情吗?
  • @MohammadZekrallah Xamarin 在 iOS 上对 .NET 的 HttpWebRequest 的实现可能存在一些问题。您可以尝试改用新的JsonHttpClient that's based on HttpClient,它可以让您使用ModernHttpClient
  • @mythz 太快了!当然..如果出现任何问题,我会尝试并在此处和服务堆栈问题跟踪器中发布我的结果..
  • 我一直在研究现代 http 客户端,但我担心该项目还不够成熟,无法用于生产,尤其是在我在 github 存储库中看到它的问题之后 .. @mythz if您有一些记录在案的案例或代码,其中 xamarin 的实现被证明存在错误或需要更多稳定性,请将其交给我,我可以将其交给他们的支持,因为我有付费的 xamarin 许可证。谢谢
猜你喜欢
  • 2018-07-10
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多