使MVC站点地图每个会话唯一,而不是每个用户
本文关键字:用户 会话 MVC 站点 地图 唯一 | 更新日期: 2023-09-27 18:18:41
我们的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);
}
}
}
然后像这样注入(StructureMap示例所示):
// 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