注入 - AppFabric 缓存的 InSessionScope 扩展问题

inject - InSessionScope Extension problems with AppFabric Cache

Ninject 不为网站提供 InSessionScope 绑定,因此我们创建了自己的扩展:

public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
   return parent.InScope(SessionScopeCallback);
}

private const string _sessionKey = "Ninject Session Scope Sync Root";

private static object SessionScopeCallback(IContext context)
{
    if (HttpContext.Current.Session[_sessionKey] == null)
    {
        HttpContext.Current.Session[_sessionKey] = new object();
    }
    return HttpContext.Current.Session[_sessionKey];
}

在我们使用标准的本地 SessionStore 之前,此扩展工作正常。

但是我们更改了 SessionStore,我们现在使用“AppFabricCacheSessionStoreProvider”,并且该存储不再位于本地计算机上,而是位于服务器上。

问题是 Ninject 试图解析来自服务器而不是本地内存的序列化和反序列化对象的引用,因此 ninject 无法找到参考资料。结果是,ninjects 总是创建一个新对象,SessionScope 不再工作。

编辑 1:

我们正在使用此功能

https://msdn.microsoft.com/en-us/library/hh361711%28v=azure.10%29.aspx

这里我可以使用标准 "HttpContext.Current.Session" 对象,列表内容存储在服务器上而不是本地机器上。

所以在架构上你有一个问题,你需要在某个地方存储 AppFabric 的设置,这是你的静态方法的问题。但是假设你创建了一个 public static class 像这样:

public static class AppCache
{

    public static DataCache Cache { get; private set; }

    static AppCache()
    {
        List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>(1);

        servers.Add(new DataCacheServerEndpoint("ServerName", 22233)); //22233 is the default port

        DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration
        {
            Servers = servers,
            LocalCacheProperties = new DataCacheLocalCacheProperties(),
            SecurityProperties = new DataCacheSecurity(),
            RequestTimeout = new TimeSpan(0, 0, 300),
            MaxConnectionsToServer = 10,
            ChannelOpenTimeout = new TimeSpan(0, 0, 300),
            TransportProperties = new DataCacheTransportProperties() { MaxBufferSize = int.MaxValue, MaxBufferPoolSize = long.MaxValue }
        };

        DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);

        var _factory = new DataCacheFactory(configuration);

        Cache = _factory.GetCache("MyCache");
    }
}

然后你可以像这样更改扩展名:

public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
   return parent.InScope(SessionScopeCallback);
}

private const string _sessionKey = "Ninject Session Scope Sync Root";

private static object SessionScopeCallback(IContext context)
{
    var cachedItem = AppCache.Cache.Get("MyItem"); // IMPORTANT: For concurrency reason, get the whole item down to method scope.
    if (cachedItem  == null)
    {
        cachedItem = new object();
        AppCache.Cache.Put("MyItem", cachedItem);
    }
    return cachedItem;
}

我发现了一个 "Solution" 目前还可以使用但它并不完美,因为我避免使用 AppFabric Store 和 Localstore 作为对象引用。

    public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
    {
       return parent.InScope(SessionScopeCallback);
    }

    public static Dictionary<string, object> LocalSessionStore = new Dictionary<string, object>();

    private const string _sessionKey = "Ninject Session Scope Sync Root";

    private static object SessionScopeCallback(IContext context)
    {
        var obj = new object();
        var key = (string)HttpContext.Current.Session[_sessionKey];

        if (string.IsNullOrEmpty(key))
        {
            var guid = Guid.NewGuid().ToString();
            HttpContext.Current.Session[_sessionKey] = guid;
            LocalSessionStore.Add(guid, obj);
        }
        else if(!LocalSessionStore.ContainsKey(key))
        {
            LocalSessionStore.Add(key, obj);
            return LocalSessionStore[key];
        }
        else if (LocalSessionStore.ContainsKey(key))
        {
            return LocalSessionStore[key];
        }

        return HttpContext.Current.Session[_sessionKey];
    }
}