Asp.net-Mvc

如何在 ASP.NET MVC 2+ 中將 DI / IoC 容器與模型綁定器一起使用?

  • October 8, 2012

假設我有一個使用者實體,我想在建構子中將它的 CreationTime 屬性設置為 DateTime.Now。但是作為單元測試採用者,我不想直接訪問 DateTime.Now 而是使用 ITimeProvider :

public class User {
   public User(ITimeProvider timeProvider) {
       // ...
       this.CreationTime = timeProvider.Now;
   }

   // .....
}

public interface ITimeProvider { 
   public DateTime Now { get; }
}

public class TimeProvider : ITimeProvider {
   public DateTime Now { get { return DateTime.Now; } }
}

我在我的 ASP.NET MVC 2.0 應用程序中使用 NInject 2。我有一個 UserController 和兩個 Create 方法(一個用於 GET,一個用於 POST)。GET 的一個是直截了當的,但 POST 的一個不是那麼直截了當,也不是那麼直截了當:P 因為我需要弄亂模型綁定器來告訴它獲取 ITimeProvider 實現的引用以便能夠構造一個使用者實例。

public class UserController : Controller {

   [HttpGet]
   public ViewResult Create() {
        return View();
   }

   [HttpPost]
   public ActionResult Create(User user) {

        // ...

   }
}

我還希望能夠保留預設模型綁定器的所有功能。

有沒有機會解決這個簡單/優雅/等等?:D

不如ITimeProvider試試這個:

public class User 
{
   public Func<DateTime> DateTimeProvider = () => DateTime.Now;

   public User() 
   {
       this.CreationTime = DateTimeProvider();
   }
}

在你的單元測試中:

var user = new User();
user.DateTimeProvider = () => new DateTime(2010, 5, 24);

我知道這不是很優雅,但與其弄亂模型綁定器,這可能是一個解決方案。如果這不是一個好的解決方案,您可以實現自定義模型綁定器並覆蓋CreateModel方法,您將在模型的建構子中註入依賴項。

幾點觀察:

不要注入依賴項只是為了在建構子中查詢它們

沒有理由將 ITimeProvider 注入使用者只是為了Now立即呼叫。只需直接注入創建時間:

public User(DateTime creationTime)
{
    this.CreationTime = creationTime;
}

與 DI 相關的一個非常好的經驗法則是建構子不應該執行任何邏輯

不要將 DI 與 ModelBinders 一起使用

ASP.NET MVC ModelBinder 是執行 DI 的一個非常糟糕的地方,特別是因為您不能使用建構子注入。唯一剩下的選項是靜態服務定位器反模式

ModelBinder 將 HTTP GET 和 POST 資訊轉換為強類型對象,但從概念上講,這些類型不是域對象,而是類似於Data Transfer Objects

一個更好的 ASP.NET MVC 解決方案是完全放棄自定義 ModelBinders,而是明確接受從 HTTP 連接接收到的不是完整的域對象

您可以使用簡單的查找或映射器來檢索控制器中的域對象:

public ActionResult Create(UserPostModel userPost)
{
   User u = this.userRepository.Lookup(userPost);
   // ...
}

this.userRepository注入的依賴項在哪裡。

引用自:https://stackoverflow.com/questions/2899680