如何使用ASP.NET MVC通用控制器来填充正确的模型

Mou*_*Mou 6 c# asp.net-mvc

我问了一个关于ASP.NET MVC Generic Controller的问题,这个答案显示了这样一个控制器:

public abstract class GenericController<T> 
    where T : class
{
    public virtual ActionResult Details(int id)
    {
        var model = _repository.Set<T>().Find(id);
        return View(model);
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个可以像这样实现.

public class FooController : GenericController<Foo>
{

}
Run Code Online (Sandbox Code Playgroud)

现在当有人请求/ Foo/Details/42时,权利从_repository中被提取出来Set<Foo>(),而不必为此写任何内容FooController.

他解释的方式很好,但我认为我想为产品和客户开发通用控制器,我不会使用EF来加载产品和客户模型,而是使用MS数据访问应用程序块.

public abstract class GenericController<T> 
        where T : class
    {
        public virtual ActionResult Details(int id)
        {
            //var model = _repository.Set<T>().Find(id);
            var model =customer.load(id);
            or 
            var model =product.load(id);
            return View(model);
        }
    }
Run Code Online (Sandbox Code Playgroud)

因此,当请求到来时,/Customer/Details/42 or /product/Details/11通用控制器的详细信息方法将调用,但我们如何检测该请求来自哪个控制器并相应地实例化右类以加载正确的模型.

如果请求来自客户,那么我需要从详细操作方法加载客户详细信息,或者如果请求来自产品,那么我需要从通用控制器的详细操作方法加载产品详细信息.

如何使用泛型来获取T实体框架数据块的类型数据集?

Dmy*_*nko 12

您可以创建一组存储库来处理您的实体,例如CustomerRepository,ProductRepository从基本接口

public interface IBaseRepository
{
  T Get<T>(int id);
  void Save<T>(T entity);
}
Run Code Online (Sandbox Code Playgroud)

然后使用任何DI框架扩展具有存储库类型及其实例的基本控制器类

public abstract class GenericController<T, TRepo> 
        where T : class
        where TRepo : IBaseRepository, new()
    {
        private IBaseRepository repository;

        public GenericController() 
        {
            repository = new TRepo();
        }

        public virtual ActionResult Details(int id)
        {
           var model =repository.Get<T>(id);
           return View(model);
        }
    }
Run Code Online (Sandbox Code Playgroud)

示例 CustomerController

public class CustomerController : GenericController<Customer, CustomerRepository>
{

}
Run Code Online (Sandbox Code Playgroud)

CustomerRepository的位置:

public class CustomerRepository : IBaseRepository
{
  public T Get <T>(int id) 
  {
    // load data from DB
    return new Customer();
  }
}
Run Code Online (Sandbox Code Playgroud)


Hen*_*ema 7

当您的应用程序的大小和复杂性超出某一点时,我不认为将这样的数据访问和业务逻辑放在控制器中是明智的.您应该创建处理数据访问的存储库,并从消费者那里抽象出技术(EF,普通ADO.NET等).您可以在控制器中使用这些存储库,但这意味着您的控制器仍然包含您不想要的业务逻辑.控制器应该很薄.

我所做的是在我的存储库和控制器之间创建一个服务层,其中包含业务逻辑和委托对存储库的数据访问.我在我的控制器中使用这些服务来获取我的域模型,我将它们映射到视图模型.你需要一个Inversion of Control容器来将这些层"粘合"在一起,并在它们之间提供松散的耦合.

搜索"c#mvc存储​​库和服务模式"将导致大量示例.我发现这篇文章很好,除了他从他的服务而不是域模型返回视图模型的事实.

这只是我的2美分,请记住,以上所有内容仅适用于您拥有"中档"应用程序而非典型的教程/试用网站.

  • 我写了这个例子,我同意你不应该在你的控制器中直接使用ORM.然而,这是每个MVC教程的工作原理,因此这是向前发展的最简单方法.Web上有大量示例和教程,介绍如何将数据访问转移到服务层,让控制器与服务层而不是数据层进行通信.但是,此服务层也可以实现为通用存储库,使您可以再次使用通用控制器. (2认同)

Cod*_*ter 5

鉴于我在另一个问题中的免责声明以及我在这里解释为什么这不是最终解决方案的评论,我将尝试提供更具体的实现:

public abstract class GenericController<T> : Controller
    where T : class
{
    protected YourEFContext _dataSource;

    public GenericController()
    {
        _dataSource = new YourEFContext();
    }

    public virtual ActionResult Details(int id)
    {
        var model = _dataSource.Set<T>().Find(id);
        return View(model);
    }
}

public class CustomerController : GenericController<Customer>
{

}
Run Code Online (Sandbox Code Playgroud)

这是从实体框架上下文加载/Customers/Details/42具有 ID 的加载客户所需的所有代码42。“通用”部分由实体框架的DbContext.Set<T>()方法解决,该方法返回DbSet<TEntity>适当实体的 ,在这种情况下DbSet<Customer>您可以查询。

话虽如此,实际使用此代码存在很多问题:

  • 您不想让您的控制器知道您的数据访问。如您所见,YourEFContext控制器中使用了一个属性,将其与实体框架紧密耦合。您将希望在存储库模式中将其抽象化。
  • 你不希望你的控制器实例化它的数据访问,这应该被注入。
  • 您不希望控制器返回数据库实体。您正在寻找 ViewModels 和 Mapper。
  • 您不希望您的控制器进行数据访问。将数据访问移到还包含您的业务逻辑的服务层中,通过存储库模式再次对其进行抽象。

现在您的问题实际上是“企业库数据块是否有类似的方法GetDataSet<T>”,因此您不必在通用控制器中引用customer和product,但不幸的是我找不到它,因为我没有使用 EntLib数年。如果您显示当前用于访问数据库的代码,将会有所帮助。

您正在寻找的最终目标:

[       MVC             ] <=> [         Service         ] <=> [   Repository   ]
View ViewModel Controller     BusinessModel BusinessLogic     DataModel Database
Run Code Online (Sandbox Code Playgroud)

您的控制器仅与您的服务对话以创建/读取/更新/删除 BusinessModels,并执行 ViewModels 和 BusinessModels 之间的映射(在<=>)。该服务包含业务逻辑和业务模型(使用 WCF 时为 DataContacts),并依次映射 ( <=>) 和来自 DataModels 并与您的存储库对话以保留您的模型。

我知道这一次可能有点难以掌握,这可能就是大多数 ASP.NET MVC 教程从一个应用程序中的所有三层开始的原因。看看ProDinner以获得更合适的方法。