这个问题似乎只存在于在 Ubuntu 上运行的 Mono(在我的例子中是版本 2.10)中。我的控制台程序在 Windows 上按预期运行,即使在 Windows 上使用 Mono 时也是如此。
我在我们的 API 上有一项服务需要身份验证。访问它的客户端像往常一样进行身份验证并卡在 ss-id 上,稍后放入 cookie 并添加到 JsonServiceClient cookie 容器中。我以这种方式调用 JsonServiceClient:
internal class ApiClient
{
// Service client
private JsonServiceClient _ServiceClient;
internal JsonServiceClient ServiceClient
{
get
{
if (_ServiceClient == null)
{
_ServiceClient = new JsonServiceClient(globals.ApiUrl);
}
var CookieQuery = (from c in globals.AuthCookieContainer
where c.Name == "ss-id"
where !c.Expired
select c);
if (CookieQuery.Count() > 0)
{
_ServiceClient.CookieContainer.Add(CookieQuery.FirstOrDefault());
}
return _ServiceClient;
}
set
{
_ServiceClient = value;
}
}
很简单。其目的是简单地返回现有服务客户端或已包含身份验证 token 的新服务客户端。它似乎在我使用它的其他任何地方都工作得很好。
为了在程序的其他地方使用客户端从 API 服务器获取一些对象,我调用如下:
return ClientClass.ServiceClient.Get(new ServiceModel.DueRequest()).Result;
如上所述,执行此控制台应用程序在 Windows 和 Mono for Windows 上按预期运行。客户端被调用,连接到服务器并按预期抓取对象列表。
但在 Linux 上,我尝试使用“~$ mono MyApp.exe/arg1/arg2/arg3”运行应用程序,它以 302 响应,尝试将我重定向到登录位置。自然地,这表明 ServiceStack 从未被告知我针对此特定请求的现有 session 。所以...为了确保我仔细查看了托管我们的 API 的机器(它本身由 Apache/mod_mono 托管),它看起来好像初始身份验证(使用 credentialsauthprovider)正在按预期工作,我正在取回 SS-要使用的ID等
深入挖掘,我查看了发送到 Apache 的 header 。从 Windows 执行此控制台应用程序时,带有 ss-id 的 cookie 应包含在 DueRequest 请求中(如上所示)。 但是,当在 Linux 上使用 Mono 运行完全相同的可执行文件时,cookie 不存在。同样,这是运行完全相同版本的可执行文件和 ServiceStack DLL。
我不得不猜测这更多是 Mono 的问题,我只是想知道在 Linux/ServiceStack 上一起使用 Mono 之前是否有人遇到过这种行为。
更多信息
为了确认没有发送 cookie,我继续在 API 服务器本身(运行 Apache/mod_mono 的服务器)上启动 TCPdump:
tcpdump -i eth0 -s 1024 -l -A port 80 | egrep -w 'cookie|Cookie'
当从“正在工作”的客户端发出请求时,我看到:
Set-Cookie: ss-pid=xZ/1TG8ED1dhxntBOPLA; path=/; expires=Sat, 04 Feb 2034 20:48:09 GMT; HttpOnly
Cookie: ss-id=xZ/1TG8ED1dhxntBOPLA
从 Linux 终端使用 Mono 运行时:
Set-Cookie: ss-pid=TTIJ2tYOXjRwUwCfv/sn; path=/; expires=Sat, 04 Feb 2034 20:49:17 GMT; HttpOnly
服务器显然使用 cookie 进行响应...但在第二个示例中,客户端从未发送过 cookie。
最佳答案
我一直使用 Mono,没有这个问题。我创建了一个完全可用的控制台应用程序(如下) 并在 Mono 2.10.6 和 Mono 3.2.6 上进行了测试。 ServiceStack v4.0.9
我建议您试用该应用程序,看看它是否通过。
测试应用:
using System;
using ServiceStack;
namespace TestCookies
{
class MainClass
{
public static void Main()
{
// Very basic console host
var appHost = new AppHost(500);
appHost.Init();
appHost.Start("http://*:9000/");
// Make client request
var client = new JsonServiceClient("http://localhost:9000");
Console.WriteLine("Has cookie? {0}", client.Get(new HasCookieRequest()));
client.Get(new SetCookieRequest());
Console.WriteLine("Set cookie? {0}", client.CookieContainer.Count > 0);
Console.WriteLine("Has cookie? {0}", client.Get(new HasCookieRequest()));
Console.ReadKey();
}
}
public class AppHost : AppHostHttpListenerPoolBase
{
public AppHost(int poolSize) : base("Cookie Test Service", poolSize, typeof(CookieTestService).Assembly) {}
public override void Configure(Funq.Container container)
{
Config = new HostConfig {
DebugMode = true,
};
}
}
[Route("/SetCookie","GET")]
public class SetCookieRequest : IReturnVoid {}
[Route("/HasCookie","GET")]
public class HasCookieRequest : IReturn<bool> {}
public class CookieTestService : Service
{
public void Get(SetCookieRequest request)
{
Response.SetCookie("ss-id","1234567890",DateTime.Now.AddDays(1));
}
public bool Get(HasCookieRequest request)
{
return Request.Cookies.ContainsKey("ss-id");
}
}
}
预期结果:
Has cookie? False
Set cookie? True
Has cookie? True
顺便说一句,只是从您的代码中观察到的有点偏离主题。希望您不会觉得指出这一点是厚颜无耻的。你最好改变这个:
var CookieQuery = (from c in globals.AuthCookieContainer
where c.Name == "ss-id"
where !c.Expired
select c);
if (CookieQuery.Count() > 0)
{
_ServiceClient.CookieContainer.Add(CookieQuery.FirstOrDefault());
}
进入这个:
var cookie = (from c in globals.AuthCookieContainer
where c.Name == "ss-id"
where !c.Expired
select c).FirstOrDefault();
if (cookie!=null)
{
_ServiceClient.CookieContainer.Add(cookie);
}
当您调用 .Count()
时,CookieQuery
将被计算,然后当您调用 FirstOrDefault()
时,它将被再次计算。第二种方式不行,效率更高。它非常小,但是当我开始使用 Linq 时,我也做了同样的事情。 ;)
关于c# - 从 Mono 运行时 ServiceStack 不发送 cookie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21562779/