ServiceSack Session在自托管服务器中为空

时间:2014-01-14 21:09:30

标签: c# session servicestack servicestack-bsd

Session中的Service存在问题,第二次调用时Sessionnull(已解决,请参阅帖子底部)。

我有自托管服务器和客户端,通过JsonServiceClientProtoBufServiceClient拨打服务器。

在客户端应用程序启动时,我打电话:

var baseUrl = ConfigGlobal.Host ;
var client = new JsonServiceClient(baseUrl);

var authResponse = client.Post<AuthResponse>("/auth", new Auth
{
    UserName = "test1",
    Password = "password",
    RememberMe = true
});

它有效 - OnAuthenticated它在CustomUserSession : AuthUserSession中被解雇了。

authService.SaveSession(session); 

没有帮助。

然后在一个班级中:

var client = new ProtoBufServiceClient(ConfigGlobal.Host);

client.Put(new ExcelInitialize {Filename = ""}); // OK
Model = client.Get(...); // Session is null

Get方法中的服务类存在问题,会话为null。如果我实施

 public CustomUserSession CustomUserSession
 {
    get
    {
       return SessionAs<CustomUserSession>();
    }
 }

我得到:只支持通过Singletons访问的ASP.NET请求。

我的AppHost.cs

container.Register<ICacheClient>(new MemoryCacheClient());
container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>()));

Plugins.Add(new AuthFeature(
            () => new CustomUserSession(), new IAuthProvider[]
            {
                new CustomCredentialsAuthProvider(),
                new BasicAuthProvider(),
            }));

        Plugins.Add(new RegistrationFeature());

目标:

从客户端发送一些变量并在主机上记住它们,直到用户注销。

编辑:

我的工作流程如下所示:

SomeClass1:

  • 新的auth服务客户端 - &gt;发布(新的Auth(...)); //登录确定
  • 仅此而已

SomeClass2:

  • 新服务客户端 - &gt; Put(新E); //一些初学者。
  • 服务客户端 - &gt;获取(新G);

服务G:

  • on G请求新服务客户端TryResolve();
  • client-&gt;获取(新W)

服务E

  • 在E请求CustomUserSession可访问
  • on W请求无法访问CustomUserSession。

My Custom *类看起来像Scott回答。

编辑:

以下是我准备复制和粘贴的问题代码:

    private static void Main(string[] args)
    {
        // Very basic console host
        var appHost = new AppHost();
        appHost.Init();
        appHost.Start("http://*:8082/");

        var url = "http://localhost:8082";

        var foo = new TestApp.SomeClass1(url);
        var bar = new TestApp.SomeClass2(url);

        Console.ReadKey();
    }

    public class AppService : Service
    {
        public CustomUserSession CustomUserSession
        {
            get
            {
                // Returns the typed session
                return SessionAs<CustomUserSession>();
            }
        }
    }

    public class GService : AppService
    {
        public object Get(GRequest request)
        {
            var client = base.TryResolve<EService>();

            client.Get(new WRequest());

            return new { CustomUserSession.SuperHeroIdentity };
        }
    }

    public class EService : AppService
    {
        public void Get(WRequest wRequest)
        {
            Console.WriteLine(CustomUserSession.SuperHeroIdentity);
        }

        public void Get(ERequest request)
        {
            Console.WriteLine(CustomUserSession.SuperHeroIdentity);
        }

        public void Put(ERequest request)
        {
            Console.WriteLine(CustomUserSession.SuperHeroIdentity);
        }
    }

    public class SomeClass1
    {
        public SomeClass1(string url)
        {
            var client = new JsonServiceClient(url);

            client.Post<AuthResponse>("/auth", new Auth
            {
                UserName = "clark.kent",
                Password = "kryptonite",
                RememberMe = true
            });
        }
    }

    public class SomeClass2
    {
        public SomeClass2(string url)
        {
            var client = new JsonServiceClient(url);

            client.Put(new ERequest());
            client.Get(new GRequest());
        }
    }

public class GRequest : IReturnVoid
{
}

public class ERequest : IReturnVoid
{
}

public class WRequest : IReturnVoid
{
}

解决方案(针对此问题):

  1. 在客户端应用程序中保存会话cookie,并在每次调用Webservice之前恢复它们。
  2. 使用Service :: Resolve()而不是Service :: TryResolve

1 个答案:

答案 0 :(得分:1)

您发布的代码看起来不错。因此,对您的设置来说,这可能是微不足道的。

我创建了一个简单的自托管应用,它也使用了CustomUserSessionCustomCredentialsAuthProvider,希望以此为指导将突出显示出错的地方。让我知道你是怎么过的。

using ServiceStack.CacheAccess;
using ServiceStack.CacheAccess.Providers;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Auth;
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;

namespace Testv3
{
    class MainClass
    {
        public static void Main()
        {
            // Very basic console host
            var appHost = new AppHost();
            appHost.Init();
            appHost.Start("http://*:8082/");
            Console.ReadKey();
        }
    }

    public class AppHost : AppHostHttpListenerBase
    {
        public AppHost() : base("Test Service", typeof(TestApp).Assembly) {}

        public override void Configure(Funq.Container container)
        {
            // Cache and session IoC
            container.Register<ICacheClient>(new MemoryCacheClient());
            container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>()));

            // Register the Auth Feature with the CustomCredentialsAuthProvider.
            Plugins.Add(new AuthFeature(
                () => new CustomUserSession(), 
                new IAuthProvider[]
                {
                    new CustomCredentialsAuthProvider(),
                    new BasicAuthProvider(),
                })
            );
        }
    }

    public class CustomCredentialsAuthProvider : CredentialsAuthProvider
    {
        public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
        {
            // Replace with a database lookup
            return (userName == "clark.kent" && password == "kryptonite");
        }

        public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
        {
            var customSession = session as CustomUserSession;
            if(customSession != null)
            {
                // Replace these static values with a database lookup
                customSession.FirstName = "Clark";
                customSession.LastName = "Kent";
                customSession.SuperHeroIdentity = "Superman";
            }
            authService.SaveSession(customSession, SessionExpiry);
        }
    }

    public class CustomUserSession : AuthUserSession 
    {
        // Our added session property
        public string SuperHeroIdentity { get; set; }
    }

    public static class TestApp
    {
        [Route("/SuperHeroTime", "GET")]
        public class SuperHeroTimeRequest {}

        public class TestController : Service
        {
            public CustomUserSession CustomUserSession
            {
                get 
                { 
                    // Returns the typed session
                    return SessionAs<CustomUserSession>(); 
                }
            }

            [Authenticate]
            public object Get(SuperHeroTimeRequest request)
            {
                // Return the result object
                return new { CustomUserSession.FirstName, CustomUserSession.LastName, Time = DateTime.Now.ToString(), CustomUserSession.SuperHeroIdentity };
            }
        }
    }
}

如果您将此index.html放入bin文件夹并导航至http://localhost:8082/index.html,则可以拨打该服务进行测试。

<!doctype html>
<html>
    <head>
        <title>Test</title>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script>
            function login()
            {
                $.ajax({
                    type: "POST",
                    url: "/auth/credentials",
                    contentType: "application/json",
                    data: JSON.stringify({
                        UserName: "clark.kent",
                        Password: "kryptonite",
                        RememberMe: true
                    })
                }).done(function(result){
                    getSuperHeroTime();
                });
            }
            function getSuperHeroTime()
            {
                $.ajax({
                    type: "GET",
                    url: "/SuperHeroTime",
                    contentType: "application/json",
                }).done(function(result){
                    $("#result").html(result.FirstName + " " +
                                    result.LastName + " is " +
                                    result.SuperHeroIdentity + " (" +
                                    result.Time + ")");
                });
            }
        </script>
</head>
<body>
    <h1>Super Hero Time</h1>
    <button onclick="login()">Go</button>
    <div id="result"></div>
</body>
</html>

更新

  1. 查看了编辑中提供的使用代码。您正在SomeClass1中调用Auth方法,然后不会重用JsonServiceClient。所以你的会话不会跟随。您必须重用客户端,因为客户端存储跟踪您的会话的cookie。

    SomeClass2中,您实际上是在不进行身份验证的情况下调用服务,因此会话为null。您需要为请求重复使用相同的JsonServiceClient

    您可以运行身份验证方法,然后将会话cookie传递给任何后续JsonServiceClient,以便为每个客户端保存重新身份验证。这很容易做到:

    var authClient = new JsonServiceClient(url);
    authclient.Post<AuthResponse>("/auth", new Auth {
        UserName = "clark.kent",
        Password = "kryptonite",
        RememberMe = true
    });
    
    // Get the session cookies
    var cookies = authClient.CookieContainer.GetCookies(new Uri(url));
    
    // In your other `JsonServiceClient`s set the cookies before making requests
    var anotherClient = new JsonServiceClient(url);
    anotherClient.CookiesCollection.add(cookies);
    
    anotherClient.Post( ...
    
  2. 您还尝试使用以下方法解析服务中的其他服务:

    base.TryResolve<EService>();
    

    您需要使用此功能,否则您将看到Only ASP.NET Requests accessible via Singletons are supported例外:

    base.ResolveService<EService>();