0

我们MvcSitemap已经DynamicNodeProviders实施了一些。

我们希望这些在每个会话中都是唯一的。但似乎它们对于每个用户来说都是独一无二的。

因此,如果用户登录到两个不同的浏览器或计算机,他们当前共享同一个站点地图。

我们不希望这样。

但我似乎无法弄清楚如何让它使用用户/会话组合来实现唯一性。

有没有办法使这项工作?

4

1 回答 1

1

选项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

于 2013-08-10T15:08:03.900 回答