использование Singleton для передачи учетных данных в мультитенантном приложении пахнет кодом? - PullRequest
2 голосов
/ 29 мая 2010

В настоящее время я работаю над мультитенантным приложением, использующим подход Shared DB / Shared Schema. Таким образом, мы обеспечиваем разделение данных клиента, определяя столбец TenantID во всех таблицах. По соглашению все операции чтения / записи SQL должны включать в себя предложение Где TenantID = '?' . Не идеальное решение, но задним числом это 20/20.

В любом случае, поскольку практически каждая страница / рабочий процесс в нашем приложении должна отображать данные, специфичные для арендатора, в самом начале проекта я принял (плохое) решение использовать Singleton для инкапсуляции учетных данных текущего пользователя (т. Е. TenantID и UserID). В то время я думал, что не хочу добавлять параметр TenantID к каждой сигнатуре метода в моем слое данных.

Вот как выглядит основной псевдокод:

public class UserIdentity
    {
        public UserIdentity(int tenantID, int userID)
        {
            TenantID = tenantID;
            UserID = userID;
        }

        public int TenantID { get; private set; }
        public int UserID { get; private set; }
    }

    public class AuthenticationModule : IHttpModule
    {

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest +=
                new EventHandler(context_AuthenticateRequest);
        }

        private void context_AuthenticateRequest(object sender, EventArgs e)
        {
            var userIdentity = _authenticationService.AuthenticateUser(sender);
            if (userIdentity == null)
            {
                //authentication failed, so redirect to login page, etc
            }
            else
            {
                //put the userIdentity into the HttpContext object so that
                //its only valid for the lifetime of a single request
                HttpContext.Current.Items["UserIdentity"] = userIdentity;
            }
        }
    }


    public static class CurrentUser
    {
        public static UserIdentity Instance
        {
            get { return HttpContext.Current.Items["UserIdentity"]; }
        }
    }

  public class WidgetRepository: IWidgetRepository{

    public IEnumerable<Widget> ListWidgets(){
         var tenantId = CurrentUser.Instance.TenantID;
         //call sproc with tenantId parameter
    }
  }

Как видите, здесь есть несколько запахов кода. Это синглтон, поэтому он уже не подходит для юнит-тестов. Кроме того, у вас есть очень тесная связь между CurrentUser и объектом HttpContext. По сути, это также означает, что у меня есть ссылка на System.Web в моем слое данных (дрожь).

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

1 Ответ

0 голосов
/ 29 мая 2010

CurrentUser не совсем синглтон. Я не совсем уверен, что вы бы назвали. (Синглтон по определению может существовать только по одному за раз, и любое количество экземпляров UserIdentity может быть создано по желанию с помощью внешнего кода и сосуществовать без каких-либо проблем.)

Лично я бы взял CurrentUser.Instance и либо переместил бы его в UserIdentity.CurrentUser, либо соединил бы его с любыми подобными методами и свойствами «получить глобальный экземпляр», которые у вас есть. Избавляется от класса CurrentUser, по крайней мере. Пока вы работаете над этим, сделайте свойство устанавливаемым в том же месте - оно уже установлено, просто так, чтобы (1) выглядело бы как волшебство, если бы два класса не были показаны рядом друг с другом, и (2 ) усложняет изменение порядка установки текущего идентификатора пользователя.

Не избавляется от глобального, но вы не сможете обойти это без передачи UserIdentity каждой функции, которая в этом нуждается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...