我的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
答案 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)
我建议您利用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(), ...);
}
}
我还考虑使用滑动过期,其值可以配置,默认大约30分钟 - 类似于默认的RoleManagerSection.CookieTimeout。这可能是您1小时的绝对到期时间。
最后,您应该覆盖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提到了如何执行此操作),但实际上,请查看数据库本身。角色查找不应该花费很长时间。执行支持角色查找的存储过程(它们在数据库中)并查看它是否执行缓慢。