【问题标题】:MVC - Controller to Service Layer CommunicationMVC - 控制器到服务层通信
【发布时间】:2012-03-09 00:26:18
【问题描述】:

在我的 ASP.net mvc 应用程序中,我使用服务层和存储库来保持控制器的精简。典型的详细信息只读视图如下所示:

public ActionResult Details(int id)
{
    var project = _projectService.GetById(id);

    return View(Mapper.Map<Project, ProjectDetails>(project));
}

服务层:

public class ProjectService : IProjectService
{
    public Project GetById(int id)
    {
        var project = _projectRepository.GetProject(id);

        // do some stuff

        return project;
    }
}

public class ProjectRepository : IProjectRepository
{
    public Project GetProject(int id)
    {
        return context.Projects.Find(id);
    }
}

从服务层移动到视图模型非常容易,因为自动映射器可以很容易地展平事物。将另一个直接从视图模型转移到我的服务层是我努力想出一个好的解决方案的地方。

在像创建操作这样的情况下,有什么好的方法?

[HttpPost]
public ActionResult Create(CreateProjectViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    // TODO

    return RedirectToAction("Index");
}

我很确定服务层应该对视图模型一无所知,但我也不认为 AutoMapper 在这种情况下工作得很好,因为它不擅长将平面模型制作成复杂的对象。

我的控制器与服务层通信应该是什么样的?我想让控制器中的代码尽可能简洁。

【问题讨论】:

  • 你知道,我一直发现 AutoMapper 在这种方式下也很麻烦,如果像 Resharper 这样的东西可以实现一种在复杂对象上自动创建映射的方法,那就太好了。可能会成为一个很好的插件
  • 关于使用 AutoMapper 展开:你看过stackoverflow.com/questions/3145062/…吗?
  • @rsenna 我去看看,谢谢。

标签: c# asp.net-mvc service-layer


【解决方案1】:

如果您的服务层专门用于支持您的 MVC 应用程序并且没有其他客户端,您可以考虑使用通过和从您的服务层传递的对象作为视图模型的一部分。这将消除自动映射入站调用的需要,因为您将发送控制器所需的实际对象。

您也可以考虑让服务返回域对象,这意味着应该使用服务方法而不是控制器操作来调用自动映射。

【讨论】:

  • 服务层也被 WCF 应用程序使用,因此它不能真正对视图模型进行操作。
  • 很公平。我的方法不适合你。
【解决方案2】:

到目前为止,我看到的唯一方法是手动创建一堆模型转换类,例如:

public interface ITransformer<out To, in From>
    where To : class
{
    To Transform(From instance);
}

public class SomeDataToSomeViewModelTransformer : ITransformer<SomeViewModel, SomeDataModel>
{
    public SomeViewModel Transform(SomeDataModel instance)
    {
        return new SomeViewModel
            {
                InvitationId = instance.Id,
                Email = instance.EmailAddress,
                GroupId = instance.Group.Id
            };
    }
}

还有另一个 Transformer 实现以另一种方式返回 (ViewModel -&gt; DataModel)。 并让控制器知道调用正确的变压器。

我 +1 你的问题,因为我也希望看到一个很好的干净的方法来做到这一点,而不必手动编写一堆代码来映射模型。

【讨论】:

  • 我认为这很容易奏效。使用依赖注入框架连接转换器很容易。
【解决方案3】:

您可以定义一个双向映射,然后反过来:

[HttpPost]
public ActionResult Create(CreateProjectViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    Project project = Mapper.Map<CreateProjectViewModel, Project>(model);
    // pass the project entity to your service layer
    _projectService.Create(project);

    return RedirectToAction("Index");
}

或者,如果您要更新实体,您可能首先要从服务中获取要更新的现有实体:

[HttpPost]
public ActionResult Update(CreateProjectViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    Project project = _projectService.GetById(model.Id);
    Mapper.Map<CreateProjectViewModel, Project>(model, project);

    // pass the project entity to your service layer
    _projectService.Update(project);

    return RedirectToAction("Index");
}

【讨论】:

  • 似乎有时这并不能很好地工作,因为 AutoMapper 不能轻易地从扁平模型转到复杂模型。
  • @Dismissile,好吧,这一切都取决于您如何定义映射。的确,使用 AutoMapper 更容易展平,但您也可以反过来从视图模型重建原始域模型。
  • 真的。这是您在项目中通常采用的方法吗?
  • @Dismissile,这将取决于项目的具体要求和上下文。但总的来说,这是我更喜欢的方法。
  • 最后一个问题。在您使用自动映射器从视图模型转到域模型的项目中,您的域模型是否与您的实体框架模型相同?查看模型 实体(服务层) 实体(存储库)。基本上存储库和服务层都在处理相同的对象?
猜你喜欢
  • 2012-01-22
  • 2012-01-10
  • 2012-06-01
  • 2012-11-08
  • 2021-04-15
  • 2013-03-24
  • 1970-01-01
  • 2021-03-19
  • 2014-02-19
相关资源
最近更新 更多