Asp.net网站因为每个页面上的角色签名而非常慢

时间:2012-07-09 21:20:12

标签: c# asp.net roles

我的ASP.NET应用程序中有角色。我想出了问题(我想)。应用程序中每个页面的问题都使用角色和权限。因此,它在页面加载中使用以下功能

if(Roles.IsUserInRole(“Admin”)) { //显示页面 } 其他 { //不 }

我从这个问题Poor Performance with WindowsTokenRoleProvider

找到了解决问题的方法

但是有一些不同之处 1.以上问题使用 WindowsTokenRoleProvider ,我使用 SqlRoleProvider

由于上述问题,上述解决方案并不适用于我。

到目前为止我做了什么,而且我部分成功了,我从SqlRoleProvider派生了一个类,并且包含了这个函数,它与上面的问题相同但是经过修改。我更改了web.config,使其看起来像这样

<roleManager enabled="true" cacheRolesInCookie="true" cookieName=".ASPR0L3S" cookieTimeout="117" cookieSlidingExpiration="true" cookieProtection="All" createPersistentCookie="false" defaultProvider="CustomSqlRoleProvider">
            <providers>
                <add name="CustomizedRoleProvider" type="CustomSqlRoleProvider" connectionStringName="PEGConn" applicationName="/CRM"/>
            </providers>
        </roleManager>

这是我的类中的函数,它确实获取(仅在用户登录时执行)

public override string[] GetRolesForUser(string username)
    {
        // Will contain the list of roles that the user is a member of
        List<string> roles = null;

        // Create unique cache key for the user
        string key = String.Concat(username, ":", base.ApplicationName);

        // Get cache for current session
        Cache cache = HttpContext.Current.Cache;

        // Obtain cached roles for the user
        if (cache[key] != null)
        {
            roles = new List<string>(cache[key] as string[]);
        }

        // Was the list of roles for the user in the cache?



        if (roles == null)
        {
            string[] AllRoles = GetAllRoles();
            roles = new List<string>();

            // For each system role, determine if the user is a member of that role
            foreach (String role in AllRoles)
            {
                if (base.IsUserInRole(username, role))
                {
                    roles.Add(role);
                }
            }

            // Cache the roles for 1 hour
            cache.Insert(key, roles.ToArray(), null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
        }

        // Return list of roles for the user
        return roles.ToArray();
    }

问题是当Roles.IsUserInRole函数调用相同的旧

  

System.Web.Security.Roles.IsUserInRole

功能。我甚至在我的新类中重载了这个函数,但它永远不会被执行。我基本上是缓存所有角色,以便在每个页面上刷新应用程序不会从一开始就搜索所有角色。

我是否需要从System.Web.Security.Roles.IsUserInRole派生另一个班级?有人做过吗。

每页新鲜大约需要4-8秒,这太长了。代码在VS 2008,C#3.5

5 个答案:

答案 0 :(得分:1)

我认为这也可能隐藏了应用程序设计的基本问题。您应该订阅DRY原则。不要重复自己,即不要在每个页面上重复相同的查找/代码。我建议使用会话变量,以便您可以“缓存”这些昂贵的角色查找。以下是使用会话变量的快速指南:

http://msdn.microsoft.com/en-us/library/ms178581.aspx

旁注。我看到你正在使用cookies存储你的这些“角色”。这听起来不太安全,因此我认为安全性不是本练习的主要目标。

答案 1 :(得分:1)

如果Roles.IsUserInRole(“Admin”)需要花费时间,您可以检查用户角色一次(登录时)并保存该值是会话对象。

const string IS_ADMIN_KEY; //this can be on a base class of page / master page

Session[IS_ADMIN_KEY] = Roles.IsUserInRole("Admin"); // do this when logging in

//Add this to page load
bool isAdmin = Session[IS_ADMIN_KEY]; 
if(isAdmin)) 
{ 
   // display the page 
} else 
{ 
   // don't display the page 
}

答案 2 :(得分:1)

  1. 我建议您利用GetRolesForUser的基类实现,而不是重复调用IsUserInRole,它将在每次调用时访问数据库

    public override string[] GetRolesForUser(string username)
    {
        // Create unique cache key for the user
        string key = String.Concat(username, ":", base.ApplicationName);
    
        string[] roles = HttpRuntime.Cache[key] as string[];
    
        if (roles != null)
        {
            roles = base.GetRolesForUser(username);
    
            HttpRuntine.Cache.Insert(key, roles.ToArray(), ...);
        }
    
    }
    
  2. 我还考虑使用滑动过期,其值可以配置,默认大约30分钟 - 类似于默认的RoleManagerSection.CookieTimeout。这可能是您1小时的绝对到期时间。

  3. 最后,您应该覆盖IsUserInRole以使用缓存。它可以实现如下:

    public override bool IsUserInRole(string username, string roleName)
    {
        // Case-insensitive comparison for compatibility with RolePrincipal class
        return thisGetRolesForUser(username).Contains(roleName, 
                            StringComparer.OrdinalIgnoreCase);
    }
    

答案 3 :(得分:0)

默认情况下,除了指定的提供程序之外,还有一些提供程序添加到您的应用程序中。将它们从提供者列表中删除当然可以帮助您提高性能,因为您只会使用您想要的提供程序。

<system.web>
  <membership defaultProvider="MyMembershipProvider">
    <providers>
      <clear />
      <add name="MyMembershipProvider" type="MyMembershipProvider" applicationName="My App" />
    </providers>
  </membership>
  <roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true" cookieTimeout="60">
    <providers>
      <clear />
      <add name="MyRoleProvider" type="MyRoleProvider" applicationName="My App" />
    </providers>
  </roleManager>
</system.web>

此外,我理解您是否希望将结果缓存在cookie中,而不需要在提供程序中实现任何额外的操作。将cacheRolesInCookie属性设置为True可指示.NET为您处理缓存。只要您使用System.Web.Security.Roles调用角色提供程序,.NET将处理缓存并将角色放入cookie中。

我会尝试:

<system.web>
  <roleManager enabled="true" cacheRolesInCookie="true" cookieName=".ASPR0L3S" cookieTimeout="117" cookieSlidingExpiration="true" cookieProtection="All" createPersistentCookie="false" defaultProvider="SqlRoleProvider">
    <providers>
      <clear />
      <add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="PEGConn" applicationName="/CRM"/>
    </providers>
  </roleManager>
</system.web>

答案 4 :(得分:0)

首先,你做错了。您不应该在Page_Load中放置任何内容来处理此问题。如果您的角色是静态的,那么您应该使用授权密钥web.config,如果它们是动态的,您应该在global.asax Application_AuthorizeRequest事件中执行此操作。

这将使页面生命周期更加快乐,使其更安全,更少浪费资源。

其次,你需要调查这个慢的原因。您可以通过在cookie中缓存角色来解决这个问题(JG提到了如何执行此操作),但实际上,请查看数据库本身。角色查找不应该花费很长时间。执行支持角色查找的存储过程(它们在数据库中)并查看它是否执行缓慢。