2013-05-09 49 views
1

比方說,我創建具有以下特徵的「待辦事項列表」的Web應用程序:ASP.NET MVC4庫注入到控制器,取決於當前登錄用戶

  • 有能力註冊/登錄用戶每
  • 用戶有自己的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,以便控制器不必在每個操作方法中都這樣做。這是否是一種好方法,如果是的話,我該如何實現它?如果不是,有什麼更好的選擇?

回答

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); 
    } 

    // .... 
} 

然後註冊的方法與Ninject,它可以調用來解析IIdentity爲需要它的任何部件。 (您可以決定注入IPrincipal更有用,因爲您也可以通過它獲取有關用戶角色的信息)。現在

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

,假設Ninject也構建你的控制器爲您和您已註冊爲您的應用程序需要IRepository<T>服務的組件,當前用戶IIdentity將被注入到Repository<ToDoItem>爲您Ninject。

2. 創建IRepository<ToDoItem>(或者甚至IRepository<T>如果合適的話)的擴展方法,它包裝添加Where()表達用於限制返回TODO項只限於那些相關的當前用戶。

+0

由於存儲庫注入到控制器中,使其生命週期與Web請求權綁定?但是,我想避免控制器的代碼依賴於當前記錄的用戶和使用已經返回當前用戶數據的存儲庫。例如,假設我沒有多用戶支持就首先創建了這個應用程序。現在我將如何擴展它以支持多用戶最簡單的方式?例如。控制器應保持不變,只更改存儲庫以返回當前登錄用戶的數據。希望這會更清楚我的問題... – matori82 2013-05-09 15:38:32

+0

存儲庫的生活方式與Web請求無關;它可以例如具有單身生活方式,這意味着將相同的存儲庫實例注入到每個新創建的控制器實例中。我現在更瞭解你想做什麼,但我不確定希望避免修改控制器代碼是實現它的最好方法。話雖如此,「HttpContext.User」和「Thread.CurrentPrincipal」都應設置爲代表當前用戶的「IPrincipal」,以便您可以在存儲庫方法中使用這些... – 2013-05-09 15:48:00

+0

注入「IPrincipal」或「IIdentity」可能會使存儲庫更易於測試,但這確實意味着存儲庫的生活方式需要根據每個Web請求(或更短)進行。 – 2013-05-09 15:49:38

0

對於那些,誰使用溫莎城堡:

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

注:

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

不起作用,因爲「當你註冊一個現有的實例,即使您指定一個生活方式它將被忽略。「,請參閱Windsor Castle Documentation