Question

Hope someone of you have been there. I need to do some database stuff which involve multiple tables. I am using SubSonic 3 SimpleRepository to update/access records. Now in between calls to update tables I am calling System.Web.Security.Roles methods to do some lookup. I am using single repository object to do all the updates on DAOs, but when my code hits User.IsInRole("blahblah") it throws exception MSDTC is not available on the server.

I understand it is happening because SimpleRepository is using different connection and Membership API objects are using another connection.

Is there a way to get around it or do I have to wrap the Membership API objects in my own classes?

Was it helpful?

Solution

  • You can configure membership/roles provider(s) to use the connection string you need.

  • You can inherit from any of this provider(s) and wrap the call of each method with transaction scope, controlled from outside.

OTHER TIPS

HttpContext.Current.User.IsInRole() calls RolePrincipal.IsInRole() for a user authenticated via FormsAuthentication. Internally RolePrincipal.IsInRole() calls SqlRoleProvider.GetRolesForUser(), which creates and destroys the SqlConnection object within the method.

There may be other solutions on SQL Server to get around this problem, but from the .NET side of the fence I only see the following options:

  • Implement your own role provider so that you can manage connections to the database yourself.
  • Implement your own IPrincipal object so that you can manage connections to the database yourself.
  • Pre-fetch the roles before starting your SubSonic transaction and check the list for the relevant role as needed.
  • You may not even need to store the roles, since RolePrincipal.IsInRole() caches the roles when it is called and only goes out to the database if the cache is empty or invalidated. Calling IsInRole() prior to starting your transaction will pre-populate the RolePrincipal object's cache which means subsequent calls in the middle of the SubSonic transaction will pull the roles from the cache instead of connecting to the database to get them.

I'm really not convinced that the last idea is a good one, as I'm sure there are plenty of ways this can go wrong. I think the easiest solution is to pre-fetch the roles prior to beginning the SubSonic transaction.

I hope that helps.

EDIT: For completeness, here is the implementation of RolePrincipal.IsInRole() as seen in Reflector:

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top