API транзакций и членства в ASP.NET - PullRequest
3 голосов
/ 28 апреля 2011

Надеюсь, кто-то из вас был там. Мне нужно сделать некоторые вещи базы данных, которые включают в себя несколько таблиц. Я использую SubSonic 3 SimpleRepository для обновления / доступа к записям. Теперь между вызовами для обновления таблиц я вызываю System.Web.Security.Roles методы для поиска. Я использую один объект репозитория для выполнения всех обновлений в DAO, но когда мой код достигает User.IsInRole("blahblah"), возникает исключение MSDTC is not available on the server.

Я понимаю, что это происходит потому, что SimpleRepository использует другое соединение, а Membership API объекты используют другое соединение.

Есть ли способ обойти это или мне нужно обернуть Membership API объекты в моих собственных классах?

Ответы [ 2 ]

1 голос
/ 29 апреля 2011
  • Вы можете настроить провайдера (-ов) членства / ролей для использования нужной вам строки подключения.

  • Вы можете наследовать от любого из этих провайдеров и заключать вызов каждого метода в область транзакции, контролируемую извне.

0 голосов
/ 29 апреля 2011

HttpContext.Current.User.IsInRole() вызывает RolePrincipal.IsInRole() для пользователя, аутентифицированного с помощью FormsAuthentication. Внутренне RolePrincipal.IsInRole() вызывает SqlRoleProvider.GetRolesForUser(), что создает и уничтожает объект SqlConnection в методе.

Могут быть и другие решения на SQL Server, чтобы обойти эту проблему, но со стороны .NET я вижу только следующие варианты:

  • Реализация собственного поставщика ролей, чтобы вы могли самостоятельно управлять подключениями к базе данных.
  • Реализуйте свой собственный объект IPrincipal, чтобы вы могли самостоятельно управлять подключениями к базе данных.
  • Предварительно извлеките роли перед началом транзакции SubSonic и при необходимости проверьте список на наличие соответствующей роли.
  • Возможно, вам даже не нужно хранить роли, поскольку RolePrincipal.IsInRole() кэширует роли при вызове и отправляется в базу данных только в том случае, если кэш пустой или недействителен. Вызов IsInRole() перед началом транзакции предварительно заполнит кэш объекта RolePrincipal, что означает, что последующие вызовы в середине транзакции SubSonic будут извлекать роли из кэша, а не подключаться к базе данных для их получения.

Я действительно не уверен, что последняя идея хорошая, так как я уверен, что есть много способов, которые могут пойти не так. Я думаю, что самое простое решение - предварительно выбрать роли до начала транзакции SubSonic.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Для полноты, вот реализация RolePrincipal.IsInRole(), как видно в 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);
}
...