ASP.Net MVC2中Controller和Repository的职责范围是什么?

4
我将翻译如何使用存储库构建ASP.Net MVC2 Web应用程序的结构。许多示例、教程和书籍都采用以下方式构建应用程序:
public interface IProductsRepository
{
    IQueryable<Product> Products { get; }
}

public class SqlProductsRepository : IProductsRepository
{
    public Table<Product> productsTable;

    public IQueryable<Product> Products
    {
        get { return productsTable }
    }
}

public class ProductsController : Controller
{
    IProductsRepository productsRepository;
    public ProductsController(IProductsRepository productsRepository)
    {
       // set the Repository
    }

    public ActionResult GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount)
    {
        // Do LINQ query 
        return View(from p in productsRepository
                    where p.PublishedOn != null 
                    orderby p.ProductId descending 
                    select to(p))
                    .Skip((page  - 1) * pageSize)
                    .Take(pageSize)
                    .ToList());
    }
}

我不明白的一件事是为什么Linq查询要放在控制器中。

我想知道为什么这样做是不正确的:

public class SqlProductsRepository : IProductsRepository
{
    // set data model stuff here

    public List<Product> GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount) {
        // DO LINQ Query in here
    }
}

public class ProductsController : Controller
{
    // set repository stuff here

    public ActionResult GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount)
    {       
        return View(productsRepository.GetLatestPublishedProducts(pageSize, page, totalItemCount));
    }
}
3个回答

9
您应该采用第二个例子。仓库应该处理所有数据访问。控制器只应获取已过滤/排序的数据并将其传递给视图。控制器不应负责任何数据或业务逻辑。它只应负责检索数据并传递它。在编写控制器代码时,我会问自己这个问题:“如果我要在WinForms中编写此应用程序,我是否需要再次编写此代码?”因此,您的IProductsRepository将具有方法GetLatestPublishedProducts,然后您将在SqlProductsRepository中实现它。各自的职责是:仓库-从数据库获取数据,控制器-将数据传递给视图进行呈现。您还可以进一步将任何业务逻辑分离出来,以便控制器本身避免使用存储库。因此,您将拥有第三个服务层,位于控制器和存储库之间。

谢谢 :D 这正是我所想的。读这些书时,看到错误的东西有点令人沮丧。有没有人知道一个好的真实世界 MVC2 项目,我可以查看源代码? - sf.
@sf - 很多书的问题在于它们是为了教你如何使用某个东西,而不是如何设计你的应用程序。这就是为什么你应该买一本不错的设计模式书或DDD书来辅助学习的原因。 - djdd87

4

检查不同类的意图。

  • Repository: 提供对数据库的访问
  • Controller: 控制网站的流程(我知道,有更好的意图)

这意味着,如果您将Linq视为主要业务逻辑,则它不应出现在任何一个类中。 我会创建一个ProductService,其中包含所有这些抽象调用,因为它们将被广泛重用。

服务中应该包含什么:

from p in productsRepository
                    where p.PublishedOn != null 
                    orderby p.ProductId descending 
                    select to(p))

控制器应该包含什么内容:

from p in productService.GetLatestPublishedProducts()
                    .Skip((page  - 1) * pageSize)
                    .Take(pageSize)

如果可能的话,请使用IEnumerable而不是List。


谢谢你。我也会确保使用IEnumerable。 - sf.

1

让你的控制器保持精简是一个目标。这将有助于保持事物的秩序。使用存储库来处理所有数据访问逻辑。我还包括一个服务层来处理其他业务和验证逻辑。因此,我的控制器、服务和存储库方法类似于Create,看起来像这样:

// Controller
public ActionResult Create(MyModel myModel)
{
    if (!_service.CreateMyModel(myModel)) 
    {
        return View(myModel);
    }

    return RedirectToAction("Index");
}

// Service
public bool CreateMyModel(MyModel myModel)
{
    // Validation logic
    if (!ValidateMyModel(myModel))  
    {
        return false;
    }

    return _repository.CreateMyModel(myModel);
}

// Repository
public book CreateMyModel(MyModel myModel)
{
    _entities.AddToMyModelsSet(myModel);
    try
    {
        _entities.SaveChages();
        return true;    
    }
    catch
    {
        return false;
    }
}

验证不应该由MVC完成吗?你有ModelState.IsValid,这是什么用例,你会将其转移到服务并手动执行吗? - cRichter
你可以将验证交给MVC。我在我的MVC应用程序中使用自定义的ModelWrapper和Validation类,它允许我执行特定/附加的验证。最终ValidateMyModel方法返回ModelState.IsValid。 - gnome

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接