希望你们中的某个人去过那里。我需要做一些涉及多个表的数据库工作。我正在使用SubSonic 3 SimpleRepository来更新/访问记录。现在,在更新表的调用之间,我调用System.Web.Security.Roles
方法来执行一些查找。我正在使用单个存储库对象对 DAO 进行所有更新,但是当我的代码命中User.IsInRole("blahblah")
时它会抛出异常MSDTC is not available on the server
。
我知道它正在发生,因为SimpleRepository
正在使用不同的连接,而Membership API
对象正在使用另一个连接。
有没有办法绕过它,或者我必须将Membership API
对象包装在我自己的类中?
-
可以将成员身份/角色提供程序配置为使用所需的连接字符串。
-
您可以从任何此提供程序继承,并将每个方法的调用包装为事务范围,从外部控制。
HttpContext.Current.User.IsInRole()
对通过 FormsAuthentication 进行身份验证的用户进行RolePrincipal.IsInRole()
调用。在内部RolePrincipal.IsInRole()
调用 SqlRoleProvider.GetRolesForUser()
,这会在方法中创建和销毁SqlConnection
对象。
SQL Server 上可能还有其他解决方案可以解决此问题,但从围栏的 .NET 端,我只看到以下选项:
- 实现您自己的角色提供程序,以便您可以自己管理与数据库的连接。
- 实现您自己的
IPrincipal
对象,以便您可以自己管理与数据库的连接。 - 在开始 SubSonic 事务之前预获取角色,并根据需要检查相关角色的列表。
- 您甚至可能不需要存储角色,因为
RolePrincipal.IsInRole()
在调用角色时缓存角色,并且仅在缓存为空或无效时才发送到数据库。在开始事务之前调用IsInRole()
将预填充RolePrincipal
对象的缓存,这意味着SubSonic 事务中间的后续调用将从缓存中提取角色,而不是连接到数据库以获取它们。
我真的不相信最后一个想法是一个好主意,因为我确信有很多方法可能会出错。我认为最简单的解决方案是在开始 SubSonic 事务之前预获取角色。
我希望这有所帮助。
编辑:为了完整起见,以下是反射器中看到的RolePrincipal.IsInRole()
的实现:
public bool IsInRole(string role)
{
if (this._Identity == null)
{
throw new ProviderException(SR.GetString("Role_Principal_not_fully_constructed"));
}
if (!this._Identity.IsAuthenticated || (role == null))
{
return false;
}
role = role.Trim();
if (!this.IsRoleListCached)
{
this._Roles.Clear();
foreach (string str in Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name))
{
if (this._Roles[str] == null)
{
this._Roles.Add(str, string.Empty);
}
}
this._IsRoleListCached = true;
this._CachedListChanged = true;
}
return (this._Roles[role] != null);
}