2

依赖倒置原则指出高层模块不应该依赖于低层模块。两者都应该依赖于抽象。我明白这个道理。但是当我使用 ASP.NET MVC 时,我经常将我的控制器方法设置为:

  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,因为我的控制器的结果取决于 User 类。在这种情况下,我想不出一种将 Controller 与我的 User 类分离的方法。有没有办法摆脱这种依赖?或者在这种情况下这样做就可以了吗?

4

4 回答 4

3

创建一个接口并将其实现注入您的 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)将所需的接口实现注入到控制器中。

如果您想引入更多层,例如业务层、服务层,请遵循相同的方法。

于 2015-04-21T15:15:33.953 回答
2

如果您的应用程序结构如下所示,那么您正在实施 DIP(依赖倒置原则)。

DIP 表示应用程序中的层应该依赖于接口,而不是实现。像下面这样,Service取决于IDatabase不是MyDatabase

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. 我建议看一下3-tier-architecture这样做你会提高你对SOLID的理解并且你的应用程序会更有条理。

  2. 如果在您的情况下MyDatabase是一个更高的模块User,那么您不尊重 DIP 原则,因为您的控制器使用了一个较低的模块。

于 2015-04-21T15:15:19.957 回答
1

DIP 或 IoC 表示高级模块不应该依赖于低级模块。两者都应该依赖于抽象。

这意味着高级类不应依赖于具体类,而应依赖于接口。

但是在这里您谈论的是似乎是DTO (Data Transfer Object)的User类。

因此,在这种情况下,您必须在最后一层使用该 DTO 来返回数据或处理数据。

但是您不应该使用实体框架提供的 POCO 类,而应该创建 DTO 类并将其用作 ViewModel。

于 2015-04-21T15:26:18.657 回答
0

Ups,这就是我在使用 ASP.NET Web API 时的做法,不确定这是否适用于 MVC 控制器。但是您可以使用Unity.MVC(v3 或 v4 或 v5)库( 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)));
        }
    }

但在运行此代码之前,您必须注册类型映射

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;
    }
于 2015-04-21T15:46:46.423 回答