MVC4 and ServiceStack session in Redis

2019-06-27 16:23发布

问题:

I have a brand new MVC4 project on which I have installed the ServiceStack MVC starter pack (version 4.0.12 from MyGET) to bootstrap the usage of the service stack sessions.

In my AppHost my custom session is configured as:

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

The custom session looks like this for testing purposes:

public class CustomUserSession : AuthUserSession
{
    public string Hello { get; set; }
}   

And the ICacheClient is registered as a redis client:

// register the message queue stuff 
var redisClients = config.Get("redis-servers", "redis.local:6379").Split(',');
var redisFactory = new PooledRedisClientManager(redisClients);
var mqHost = new RedisMqServer(redisFactory, retryCount: 2);
container.Register<IRedisClientsManager>(redisFactory); // req. to l
container.Register<IMessageFactory>(mqHost.MessageFactory);

container.Register<ICacheClient>(c =>
                        (ICacheClient)c.Resolve<IRedisClientsManager>()
                        .GetCacheClient())
                        .ReusedWithin(Funq.ReuseScope.None);      

I have then created a ControllerBase which for simplicity loads and saves the custom session for each request:

public abstract class ControllerBase :  ServiceStackController<CustomUserSession>
{
    protected override IAsyncResult BeginExecute (System.Web.Routing.RequestContext requestContext, AsyncCallback callback, object state)
    {
        ViewBag.Session = this.UserSession;
        return base.BeginExecute (requestContext, callback, state);
    }

    protected override void EndExecute(IAsyncResult asyncResult)
    {
        SaveSession(null);

        base.EndExecute(asyncResult);
    }
    public void SaveSession(TimeSpan? expiresIn = null)
    {
        Cache.CacheSet(SessionFeature.GetSessionId(), UserSession, expiresIn ?? new TimeSpan(0, 30, 0));
    }
}

I then modify the Hello property to read "World" in one of my actions, and I can clearly see with a breakpoint on the SaveSession method that the value has been properly. However, upon loading the page again and inspecting the loaded session, there's nothing set. Also, looking in the Redis database, the following blob is saved:

{
   "createdAt": "/Date(-62135596800000-0000)/",
   "lastModified": "/Date(-62135596800000-0000)/",
   "providerOAuthAccess": [],
   "isAuthenticated": true,
   "tag": 0
}

It's not saving my custom property. Can anyone tell me what I'm doing wrong / missing?

=== UPDATE ===

If I change any of the properties from the base AuthUserSession the changes to those properties are persisted - so it would seem that SS somehow decides to disregard the properties from my concrete type.

回答1:

Because AuthUserSession is a DataContract and attributes are now inherited in v4, you also need to mark each member with [DataMember], e.g:

public class CustomUserSession : AuthUserSession
{
    [DataMember]
    public string Hello { get; set; }
}