2

私は現在、共有DB/共有スキーマアプローチを採用するマルチテナントアプリケーションに取り組んでいます。IOW、すべてのテーブルにTenantID列を定義することにより、テナントデータの分離を実施します。慣例により、すべてのSQL読み取り/書き込みには、Where TenantID ='?'を含める必要があります。句。理想的な解決策ではありませんが、後知恵は20/20です。

とにかく、私たちのアプリのほぼすべてのページ/ワークフローはテナント固有のデータを表示する必要があるため、プロジェクトの最初に、現在のユーザー資格情報(つまり、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オブジェクトの間には非常に緊密な結合があります。ひいては、これは、データレイヤー(shudder)にSystem.Webへの参照があることも意味します。

上記の理由でこのシングルトンを取り除くことによって、このスプリントの技術的負債を返済したいと思います。私は、より良い実装が何であるかについていくつか考えていますが、誰かが共有できるガイダンスや教訓を持っている場合、私は非常に義務付けられます。

4

1 に答える 1

0

CurrentUserは完全にシングルトンではありません。あなたがそれを何と呼ぶのか正確にはわかりません。(定義上、シングルトンは一度に1つしか存在できず、任意の数のUserIdentityインスタンスを外部コードによって自由に作成でき、問題なく共存できます。)

個人的には、CurrentUser.Instanceを取得して、UserIdentity.CurrentUserに移動するか、同様の「グローバルインスタンスを取得する」メソッドとプロパティを組み合わせます。少なくともCurrentUserクラスを削除します。その間、プロパティを同じ場所で設定可能にします。これは、(1)2つのクラスが隣り合って表示されていない場合に魔法のように見えるように、すでに設定可能です。(2 )現在のユーザーIDの設定方法を後で変更するのが難しくなります。

グローバルを取り除くことはありませんが、それを必要とするすべての関数にUserIdentityを渡さずに、それを回避することはできません。

于 2010-05-29T03:23:52.830 に答える