C#(Web API)多层(IOC)API控制器返回类型

本文关键字:API 控制器 返回类型 IOC 多层 Web | 更新日期: 2023-09-27 18:25:28

我正在构建一个ASP-Web API应用程序,这次我想我将采用MVC模式。大多数事情我都处理得很好,但有一件事我不确定。首先,我的项目包括以下内容:

  • 数据层
  • 业务层
  • 模型层(仅是具有特性的模型)
  • 服务应用程序(这是我的控制器)

    他们每个人都在一个单独的项目中

假设我有以下控制器

public class TestController : ApiController
{
    ISomeService _someBusiness;
    public TestController(ISomeService someBusiness)
    {
        _someBusiness = someBusiness;
    }
    public **SomeModelObject** GetModelObject(ind id)
    {
        return _someBusiness .GetSomeModelObject(id);
    }
}

现在我的问题是GetModelObject(int id)的返回值。这里写着SomeModelObject。这意味着我的服务应用程序(或我的控制器)必须知道正在使用的模型的一切(所以我不认为在单独的.dll中定义它有什么意义)。一种方法是将模型(确切地说是get/set方法)定义为接口,但我认为每个模型类都有一个接口太过分了(主要是因为,正如我所说,只有属性存储在模型中),尽管如此,我还是觉得为一个只存储数据的类构建接口是不对的。那么,在这种情况下,是否使用了任何通用的响应类型(甚至是一些完全不同的方法),或者我是否必须使用我的模型类(或者我是否总是使用字符串,并且客户端正在将其转换为适当的格式)?

C#(Web API)多层(IOC)API控制器返回类型

有充分的理由使用接口来隐藏模型对象的复杂性。它当然保存数据。但它包含不必要的数据,这些数据只对数据层有意义。以这个EF模型为例:

public class Employee
{
    public int Id { get; set; }
    public string EmployeeNumber { get; set; }
    public string Name { get; set; }
    public virtual Collection<TimeCard> TimeCards { get; set; }
    public int DepartmentId { get; set; }
    public virtual Department Department { get; set; }
}

这是一款仙气十足的EF模型。它包含一个代理密钥Id和一个外键DepartmentId。除了数据库之外,这些值是没有意义的,而且从扩展的角度来说,对于实体框架也是如此。EmployeeNumber是唯一标识用户域中实体的自然密钥。

在数据库访问之外,实际上应该只处理自然数据值。您可以通过在业务层中声明另一个数据承载类并执行映射来实现这一点,或者更好的想法是使用接口来隐藏所有无用的成员。

public interface IEmployee
{
    string EmployeeNumber { get; }
    string Name { get; set; }
    ICollection<ITimeCard> TimeCards { get; }
    IDepartment Department { get; set; }
}

请注意,界面中缺少一些setter。您永远不会想更改EmployeeNumber,因为它是实体的自然键。同样,您永远不会将集合对象指定给TimeCards属性。您只能对它们进行迭代、添加或删除。

现在您的员工类变成

public class Employee : IEmployee
{
    public int Id { get; set; }
    public string EmployeeNumber { get; set; }
    public string Name { get; set; }
    public virtual Collection<TimeCard> TimeCards { get; set; }
    ICollection<ITimeCard> IEmployee.TimeCards { get { return TimeCards; } }
    public int DepartmentId { get; set; }
    public virtual Department Department { get; set; }
    IDepartment IEmployee.Department { get { return Department; } set { Department = value; } }
}

在您的业务层及以上,您将只使用变量IEemployee、IDepartment和ITimeCard。因此,您将更严格的API暴露给更高层,这是一件好事。

您可以尝试在控制器级别使用一种通用方法:

public class BusinessController<T> : ApiController
{
    ISomeService _someBusiness;
    public TestController(ISomeService someBusiness)
    {
        _someBusiness = someBusiness;
    }
    public T GetModelObject(ind id)
    {
        return _someBusiness.GetSomeModelObject(id);
    }
}

最后,您的控制器继承自BusinessController而非ApiController:

public class TestController : BusinessController<SomeModelObject>
{
}

您还可以提前使用模板,通过使用IoC容器和引导程序来注入正确的"ISomeService"。