我们MvcSitemap
已经DynamicNodeProviders
实施了一些。
我们希望这些在每个会话中都是唯一的。但似乎它们对于每个用户来说都是独一无二的。
因此,如果用户登录到两个不同的浏览器或计算机,他们当前共享同一个站点地图。
我们不希望这样。
但我似乎无法弄清楚如何让它使用用户/会话组合来实现唯一性。
有没有办法使这项工作?
我们MvcSitemap
已经DynamicNodeProviders
实施了一些。
我们希望这些在每个会话中都是唯一的。但似乎它们对于每个用户来说都是独一无二的。
因此,如果用户登录到两个不同的浏览器或计算机,他们当前共享同一个站点地图。
我们不希望这样。
但我似乎无法弄清楚如何让它使用用户/会话组合来实现唯一性。
有没有办法使这项工作?
选项1:
ICacheProvider
根据会话状态实现您自己的并使用 DI 注入它。
using System;
using System.Collections.Generic;
using MvcSiteMapProvider.Web.Mvc;
using MvcSiteMapProvider.Caching;
using System.Web;
public class SessionStateCacheProvider<T>
: ICacheProvider<T>
{
public SessionStateCacheProvider(
IMvcContextFactory mvcContextFactory
)
{
if (mvcContextFactory == null)
throw new ArgumentNullException("mvcContextFactory");
this.mvcContextFactory = mvcContextFactory;
}
private readonly IMvcContextFactory mvcContextFactory;
protected HttpContextBase Context
{
get
{
return this.mvcContextFactory.CreateHttpContext();
}
}
#region ICacheProvider<ISiteMap> Members
public bool Contains(string key)
{
return (Context.Session[key] != null);
}
public Caching.LazyLock Get(string key)
{
return (LazyLock)Context.Session[key];
}
public bool TryGetValue(string key, out Caching.LazyLock value)
{
value = this.Get(key);
if (value != null)
{
return true;
}
return false;
}
public void Add(string key, LazyLock item, ICacheDetails cacheDetails)
{
// NOTE: cacheDetails is normally used to set the timeout - you might
// need to roll your own method for doing that.
Context.Session[key] = item;
}
public void Remove(string key)
{
Context.Session.Remove(key);
}
public event EventHandler<MicroCacheItemRemovedEventArgs<T>> ItemRemoved;
#endregion
// NOTE: Normally this is called by a callback from the cache when an item exprires.
// It is required to ensure there is no memory leak because a sitemap has circular references
// that need to be broken explicitly. You need to work out how to call this when the user's session
// expires.
protected virtual void OnCacheItemRemoved(MicroCacheItemRemovedEventArgs<T> e)
{
if (this.ItemRemoved != null)
{
ItemRemoved(this, e);
}
}
}
然后像这样注入它(显示结构图示例):
// Setup cache
SmartInstance<CacheDetails> cacheDetails;
this.For<ICacheProvider<ISiteMap>>().Use<SessionStateCacheProvider<ISiteMap>>();
var cacheDependency =
this.For<ICacheDependency>().Use<NullCacheDependency>();
cacheDetails =
this.For<ICacheDetails>().Use<CacheDetails>()
.Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
.Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
.Ctor<ICacheDependency>().Is(cacheDependency);
选项 2:
将用户名附加到自定义 ISiteMapCacheKeyGenerator 中的 siteMapCacheKey,并通过 DI 注入:
public class SessionBasedSiteMapCacheKeyGenerator
: ISiteMapCacheKeyGenerator
{
public UserBasedSiteMapCacheKeyGenerator(
IMvcContextFactory mvcContextFactory
)
{
if (mvcContextFactory == null)
throw new ArgumentNullException("mvcContextFactory");
this.mvcContextFactory = mvcContextFactory;
}
protected readonly IMvcContextFactory mvcContextFactory;
#region ISiteMapCacheKeyGenerator Members
public virtual string GenerateKey()
{
var context = mvcContextFactory.CreateHttpContext();
var builder = new StringBuilder();
builder.Append("sitemap://");
builder.Append(context.Request.Url.DnsSafeHost);
builder.Append("/?sessionId=");
builder.Append(context.Session.SessionID);
return builder.ToString();
}
#endregion
}
像这样注入它(StructureMap 示例):
this.For<ISiteMapCacheKeyGenerator>().Use<SessionBasedSiteMapCacheKeyGenerator>();
请注意,需要使用外部 DI 容器。
请在此处查看我的未解决问题并向我解释为什么要在 GitHub 上执行此操作,因为它使大多数功能无用:https ://github.com/maartenba/MvcSiteMapProvider/issues/16#issuecomment-22229604