2015-04-21 71 views
2

依賴反轉原理指出高層模塊不應該依賴於低層模塊。兩者都應該依賴於抽象。我明白這個原則。但正如我使用ASP.NET MVC,我經常讓我的控制器方法爲:如何在MVC環境中實現DIP?

public ActionResult MyAction(string userValue) 
    { 
     User user = MyDatabase.GetUser(); 
     if (!user.CheckSomeCondition(userValue)) 
     { //Something failed. Try again. 
      return View(); 
     } 
     user.Update(userValue);   
     return RedirectToAction("Success"); 
    } 

我相信,因爲我的控制器的結果取決於用戶類這違反了DIP。在這種情況下,我想不出一種將Controller從我的User類中解耦的方式。有沒有辦法擺脫這種依賴?或者在這種情況下這樣做就好了嗎?

回答

2

如果您的應用程序結構如下所示,比您正在實施DIP(依賴反轉原理)。

DIP表示應用程序中的圖層應該依賴於接口,而不是實現。如下圖所示,Service取決於IDatabaseMyDatabase

public interface IDatabase { 
    Update(User user); 
} 
public interface MyDatabase : IDatabase 
{ 
    public Update(User user) { 
     // update user 
    } 
} 

public interface IService { 
    Update(string user); 
} 
public class Service : IService 
{ 
    private IDatabase _database; 
    public Service(IDatabase database) 
    { 
     _database = database; 
    } 


    public Update(User user) { 
     _database.Update(user); 
    } 
} 

DIP也說,像MvcController高層模塊不需要知道/依賴於低級別的模塊,MyDatabase

public class MvcController : Controller 
{ 
    private IService _service; 
    private IUserValidator _userValidator; 
    public MvcController(IService service, IUserValidator userValidator) // depending on abstraction 
    { 
     _service = service; 
     _userValidator = userValidator; 
    } 

    public ActionResult MyAction(string userValue) 
    { 
     if (!_userValidator.CheckSomeCondition(userValue)) 
     { //Something failed. Try again. 
      return View(); 
     } 
     User user = _service.GetUser(); 
     user.UserValue = userValue; 
     _service.Update(user);   
     return RedirectToAction("Success"); 
    } 
} 

注:

  1. 我建議看一看上三層架構這樣做,你會提高你的SOLID和應用程序的理解會更有條理。

  2. 如果在你的情況下MyDatabase是一個高於User的模塊,那麼你不尊重DIP原則,因爲你的控制器使用了較低的模塊。

2

創建一個接口並將其實現注入到您的mvc控制器。

public interface IMyDataAccess 
{ 
    User GetUser(); 
} 

立即創建您的實施。

public class MyMongoDBDataAccess : IMyDataAccess 
{ 
    public User GetUser() 
    { 
    //return a user from my fancy db 
    } 
} 

現在在你的控制器

public class HomeController : Controller 
{ 
    IMyDataAccess dao; 
    public HomeController(IMyDataAccess myDataAccess) 
    { 
    this.dao=myDataAccess; 
    } 
    public ActionResult MyAction(string userValue) 
    { 
     User user=this.dao.GetUser(); 
     //return something to the view as needed. 
    } 
} 

您可以使用任何依賴注入框架像Unity注入你的界面的期望的實施到控制器。

如果您希望引入更多層,如業務層,服務層,請遵循相同的操作。

+0

非常感謝!這看起來非常好。現在,你會在MyAction中返回什麼?如果我想根據userValue更新用戶,我需要知道是否返回錯誤或重定向。在這種情況下,MyAction可以依賴用戶嗎? –

+0

@JorgeZuverza當然可以。如果出現錯誤,請將要顯示的數據(可能是視圖模型(也可能只是一個字符串))返回到視圖。 – Shyju

1

DIP或IoC表示高級模塊不應該依賴於低級模塊。兩者都應該依賴於抽象。

這意味着高級別類不應該依賴於具體類,而應該依賴於接口。

但是在這裏你正在談論用戶類似乎是DTO(數據傳輸對象)

所以在這種情況下,您必須在最後一層使用該DTO來返回數據或處理數據。

但是,您不應該使用實體框架提供的POCO類,而應該創建並使用您的DTO類作爲ViewModels。

0

Ups,這是我在使用ASP.NET Web API時的做法,不知道這是否適用於MVC控制器。但是可以使用Unity.MVC(v3或v4或v5)lib(Unity.Mvc4)! 你可以像這樣連接它,你應該在Application_Start事件中調用這個代碼!

public static class WebApiBootstrapper 
    { 
     public static void Init(IUnityContainer container) 
     { 
      GlobalConfiguration.Configure(config => 
      { 
       config.DependencyResolver = new WebApiDependencyResolver(container); // DI container for use in WebApi 
       config.MapHttpAttributeRoutes(); 
       WebApiRouteConfig.RegisterRoutes(RouteTable.Routes); 
      }); 

      // Web API mappings 
      // All components that implement IDisposable should be 
      // registered with the HierarchicalLifetimeManager to ensure that they are properly disposed at the end of the request. 
      container.RegisterType<IYourController, YourController>(
      new HierarchicalLifetimeManager(), new InjectionConstructor(typeof(IMyDataBase))); 
     } 
    } 

但運行t這代碼之前,你必須註冊類型映射

container.RegisterType<IMyDatabse, MyDataBase>(); 

而且你還必須實現DependencyResolver類:

public class WebApiDependencyResolver : IDependencyResolver 
    { 
     protected IUnityContainer container; 

     public WebApiDependencyResolver(IUnityContainer container) 
     { 
      if (container == null) 
      { 
       throw new ArgumentNullException("container"); 
      } 
      this.container = container; 
     } 

     public object GetService(Type serviceType) 
     { 
      try 
      { 
       return container.Resolve(serviceType); 
      } 
      catch (ResolutionFailedException) 
      { 
       return null; 
      } 
     } 

     public IEnumerable<object> GetServices(Type serviceType) 
     { 
      try 
      { 
       return container.ResolveAll(serviceType); 
      } 
      catch (ResolutionFailedException) 
      { 
       return new List<object>(); 
      } 
     } 

     public IDependencyScope BeginScope() 
     { 
      var child = container.CreateChildContainer(); 
      return new WebApiDependencyResolver(child); 
     } 

     public void Dispose() 
     { 
      container.Dispose(); 
     } 
    } 

在你的控制器:

public class YourController : ApiController, IYourController 
{ 

    IDataBase _db; 
    public PlayGroundController(IDataBase db) 
    { 
     _db = db; 
    }