我认为您要问的是控制器与您的服务和数据层交互的最佳方式是什么?
一种选择是使用mediator pattern,并将服务与控制器分离。
对于 ASP.NET MVC 应用程序有一个很棒的实现:ShortBus,也可以在 nuget 上找到,我在许多项目中都使用过,到目前为止效果很好。
ShortBus 的优点之一是它支持依赖注入。在下面的示例中,所有服务都是使用 Ninject 创建的,并且需要适当的注册。
基本思想是定义控制器将使用的查询和命令,然后添加处理程序来执行实际工作。
public class AddUser : ICommand<User>
{
public string Email { get; set; }
}
然后是处理程序:
public class AddUserHandler : ICommandHandler<AddUser, User>
{
private IDatabaseService _database;
private IEmailService _email;
public AddUserHandler(IDatabaseService database, IEmailService email)
{
_database = database;
_email = email;
}
public User Handle(AddUser command)
{
bool created = _database.CreateUser(command.Email);
if (created)
{
_email.SendWelcome(command.Email);
}
}
}
然后在你的控制器中,你所要做的就是发出命令:
public class UsersController : Controller
{
private IMediator _mediator;
public UsersController(IMediator mediator)
{
_mediator = mediator;
}
public ActionResult Create(string email)
{
User user = _mediator.Send(new AddUser("foo@bar.com"));
}
}
我喜欢这种模式的地方是:
控制器不需要知道如何创建用户。它发出一个命令,并由适当的业务逻辑处理它。
每个处理程序都可以要求它需要的服务。无需使用仅由单个操作使用的服务来污染控制器。
单元测试真的很容易。我使用模拟,只需要验证 _mediator.Send() 是否使用正确的参数调用。然后为了测试处理程序,我模拟了 IDatabaseService 和 IEmailService 并验证它们在 2 种情况下被正确调用。
命令和查询可以重复使用,而且调用者永远不需要知道处理请求需要什么。
至于视图,我推荐ViewModels。
每个 View 都有自己的 ViewModel,它包含显示该特定页面所需的任何内容。然后,您可以将域对象映射到它们自己的单独 ViewModel,可能使用AutoMapper。
ViewModels 的好处是您可以适当地格式化数据(可能格式化 DateTime),然后您的视图不需要任何特殊逻辑。如果稍后您决定更新 DateTime 格式,您只需在一处进行更改。