使MVC Sitemap在每个会话中都是唯一的,而不是用户

时间:2013-06-17 16:12:36

标签: c# asp.net-mvc mvcsitemapprovider

我们的MvcSitemap已实施了一些DynamicNodeProviders

我们希望每个会话都是唯一的。但似乎每个用户都是独一无二的。

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

我们不希望这样。

但我似乎无法弄清楚如何使用User / Session组合来实现唯一性。

有没有办法让这项工作?

1 个答案:

答案 0 :(得分: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);
        }
    }

}

然后像这样注入它(显示的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