1

次の機能を備えた「TODO リスト」Web アプリケーションを作成しているとします。

  • ユーザーを登録/ログインする機能を持っている
  • 各ユーザーは、他のユーザーから独立した独自の TODO リストを持っています

そこで、クラス ToDoItem を持つ単純なモデルを作成しました。

良い方法を使用したいので、データベースから TODO アイテムを取得する汎用リポジトリを作成しました。

public interface IRepository<T>
{
    IQueryable<T> FindAll();
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);

    void Add(T newEntity);
    void Remove(T entity);

    T FindById(long id);
}

(実装は EF とコード ファーストのアプローチで行われますが、現時点では重要ではありません)

このリポジトリは、ユーザーが TODO アイテムを一覧表示、追加、削除、編集できるようにするコントローラーに挿入されます。これは、Ninject DI コンテナーを使用して具体的な実装へのリポジトリ インターフェイスを解決する、私が作成したカスタム コントローラー ファクトリを介して行われます。したがって、コントローラーは次のようになります。

public class HomeController : Controller
{
    IRepository<ToDoItem> _repository;
    public HomeController(IRepository<ToDoItem> repository)
    {
        _repository = repository;
    }

    // list all TODO items for this user
    [Authorize]
    public ActionResult ListItems()
    {
        var todoItems = _repository.FindAll();
        return View(todoItems);
    }

}

私の質問は、現在ログインしているユーザーに対してのみコントローラーが TODO リストを返すようにするための最良の方法は何ですか? 理想的には、現在ログインしているユーザーで注入および事前設定されたリポジトリでコントローラーを動作させたいと考えています。言い換えれば、アクションメソッドでこの種のコードを避けたいと思います:

    // list all TODO items for this user
    [Authorize]
    public ActionResult ListItems()
    {
        var todoItems = _repository.FindAll(User.Identity);
        return View(todoItems);
    }

可能な解決策は、どのユーザーがログに記録されているかをコントローラーファクトリーに何らかの方法で認識させて、具体的なリポジトリを初期化し、ユーザー ID を設定して、コントローラーがすべてのアクションメソッドでそれを行う必要がないようにすることだと考えていました。これは良いアプローチでしょうか?もしそうなら、どうすれば実装できますか? そうでない場合、より良い代替手段は何ですか?

4

2 に答える 2

2

これには、次の 2 つの方法のいずれかで取り組みます。

1. リポジトリのライフスタイルを Web リクエストごとにし、User.Identityこれをリポジトリ メソッド内で使用できるように依存します。例えば

public class Repository<ToDoItem> : IRepository<ToDoItem>
{
    private IIdentity _identity;

    // let the container inject the IIdentity into the repository
    // (you will need to register a service with 
    //  the container for IIdentity for this)
    public Repository(IIdentity identity)
    {
        _identity = identity;
    }

    IQueryable<ToDoItem> FindAll()
    {
        return FromSomeContext().Where(x => x.Username == _identity.Name);
    }

    // ....
}

IIdentity次に、それを必要とする任意のコンポーネントを解決するために呼び出すことができるメソッドを Ninject に登録します。IPrincipal(ユーザーロールに関する情報も取得できるため、 を注入する方が便利であると判断する場合があります)。

kernel.Bind<IIdentity>()
      .ToMethod(ctx => HttpContext.Current.User.Identity)
      .InRequestScope();

ここで、Ninject がコントローラーも構築しておりIRepository<T>、アプリケーションが必要とするサービスのコンポーネントを登録していると仮定すると、現在のユーザーはNinject によってIIdentityに注入されます。Repository<ToDoItem>

2.返される TODO アイテムを現在のユーザーに関連するものだけに制限するための式を追加するための拡張メソッドをIRepository<ToDoItem>(またはIRepository<T>適切な場合でも)作成します。Where()

于 2013-05-09T15:04:24.963 に答える
0

ウィンザー城をご利用の方へ

container.Register(
...
Component.For<IIdentity>()
    .UsingFactoryMethod(() => { return HttpContext.Current.User.Identity; })
    .LifeStyle.PerWebRequest,
...);

ノート:

Component.For<ICustomer>().Instance(HttpContext.Current.User.Identity)

「既存のインスタンスを登録すると、ライフスタイルを指定しても無視される」ため、機能しません。ウィンザー城のドキュメントを参照してください。

于 2014-04-22T10:59:05.270 に答える