Domanda

There is problem with Session in Service, Session is null on second call (solved, see bottom of the post).

I have self-hosted server and client that makes calls to server via JsonServiceClient and ProtoBufServiceClient.

On start of client application I call:

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

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

It works - OnAuthenticated it's fired in my CustomUserSession : AuthUserSession.

authService.SaveSession(session); 

didn't help.

Then in one class:

var client = new ProtoBufServiceClient(ConfigGlobal.Host);

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

There is a problem in service class in Get method Session is null. If I implement

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

I'll get: Only ASP.NET Requests accessible via Singletons are supported.

My 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());

Goal:

Send some variables from client and remember them on host until user logs off.

Edit:

My Workflow looks like this:

SomeClass1:

  • new auth service client->Post(new Auth(...)); // login ok
  • nothing more

SomeClass2:

  • new service client->Put(new E); // some init.
  • service client->Get(new G);

Service G:

  • on G request new service client TryResolve();
  • client->Get(new W)

Service E

  • on E request CustomUserSession accessible
  • on W request CustomUserSession not accessible.

My Custom* classes looks like in Scott answer.

Edit:

Here is the code of my problem ready to copy&paste:

    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
{
}

Solution (for this problem):

  1. Save session cookies in client application and restore them before every call to Webservice.
  2. Use Service::Resolve() instead of Service::TryResolve
È stato utile?

Soluzione

The code you have posted looks okay to me. So it's likely something trivial with your setup.

I have created a simple, self hosted app which also uses a CustomUserSession and a CustomCredentialsAuthProvider, hopefully using this as a guide will highlight what is going wrong. Let me know how you get on.

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 };
            }
        }
    }
}

If you put this index.html in your bin folder and navigate to http://localhost:8082/index.html you can call the service, to test it.

<!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>

Update:

  1. Having looked at your usage code provided in your edit. You are calling the Auth method in SomeClass1 and then that JsonServiceClient isn't reused. So your session won't follow. You have to reuse the client, because the client stores the cookies that track your session.

    In SomeClass2 you are effectively calling the service without authenticating, so the session is null. You need to reuse the same JsonServiceClient for your requests.

    You could run your authentication method and then pass the session cookies to any subsequent JsonServiceClient, to save re-authenticating with each client. It's easy to do:

    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. You are also trying to resolve another service within your service using:

    base.TryResolve<EService>();
    

    You need to use this instead, or you will see the Only ASP.NET Requests accessible via Singletons are supported exception:

    base.ResolveService<EService>();
    
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top