【问题标题】:When to return IHttpActionResult vs Object何时返回 IHttpActionResult vs Object
【发布时间】:2014-05-30 18:22:45
【问题描述】:

在使用 ASP.NET Web API 的示例中,我看到了两种不同的方法用于将数据返回给调用 jQuery 函数。第一种方法返回Client 类型的对象,但我不确定第二种方法返回的是什么。

方法#1(返回Client对象)

public IEnumerable<Client> GetAllClients()
{
     using (var context = new PQRSModel.PQRSEntities())
     {
       context.Configuration.ProxyCreationEnabled = false; 
       var query = context.Clients.OrderBy(c = c.OrgName);
       var customers = query.ToList();
       return customers;
     }
}

方法#2IHttpActionResult 有什么好处?)

public IHttpActionResult GetClient(int clientId)
{
     using (var context = new PQRSModel.PQRSEntities())
     {
       context.Configuration.ProxyCreationEnabled = false;
       var client = context.Clients.FirstOrDefault(c = c.ID == clientId);
       if (client == null)
       {
         return NotFound();
       }
       return Ok(client);
     }
}

如果第二种方法找到单个对象,是否有任何原因不能返回 Client 对象类型?

【问题讨论】:

    标签: c# asp.net-web-api


    【解决方案1】:

    返回IHttpActionResult 提供了一个很好的关注点分离

    您的控制器可以专注于以最明智的方式响应请求(状态代码、错误消息等)。另一个(服务)层可以专注于实际检索和转换业务数据。

    副作用是,您的控制器方法变得更加可单元测试。考虑以下简单示例:

    public class MyController : ApiController
    {
        //or better yet, dependency-inject this
        SomeService _service = new SomeService();
    
        public IHttpActionResult Get(int id)
        {
             if (id < 0)
                 return BadRequest("Some error message");
    
             var data = _service.GetData(id);
    
             if (data == null)
                return NotFound();
    
             return Ok(data);
        }
    }
    

    这个方法的逻辑不仅可以通过阅读理解,而且您现在可以更轻松自然地测试逻辑,例如(使用 NUnit 语法):

    [TestFixture]
    public class MyControllerTests
    {    
        [Test]
        public void Get_WithIdLessThan0_ReturnsBadRequest()
        {
            var controller = new MyController();
            int id = -1;
    
            IHttpActionResult actionResult = controller.Get(id);
    
            Assert.IsInstanceOf<BadRequestErrorMessageResult>(actionResult);
        }
    }
    

    同样,您可以模拟服务层并测试当您将已知的id 参数提供给控制器等时会发生什么。

    这是Unit Testing Controllers in Web Api上的一篇好文章

    【讨论】:

    • 这更像是一个创建服务层的参数,而不是返回一个IHttpActionResult。正确分离关注点后,测试操作是否引发特定异常类型与测试它是否返回给定操作结果类型一样简单。
    • 这正是我使用该测试用例作为我的 示例 的原因 - 在答案中编写代码很简单,但说明了这个想法。如果您认为我的回答不够,请添加您自己的答案。
    【解决方案2】:

    第二种方法允许您只返回状态码(如示例中的 404)、流文件内容和其他类型的非对象内容。

    【讨论】:

    • 感谢您的回答。是否仍然可以使用“IHttpActionResult”返回对象,或者当您想要返回单个对象或对象集合时应该使用第一种方法?我问的原因是示例(Microsoft 文章 - asp.net/web-api/overview/getting-started-with-aspnet-web-api/…)我正在使用返回 IHttpActionResult 的方法返回一个对象。我试图调整代码以返回一个实体框架对象。
    • 直接从方法返回对象有几个优点。方法签名将更好地定义它,并且该方法将更容易测试。可以通过抛出HttpResponseException 类型的异常而不是由IHttpActionResult 返回来返回状态码,例如找不到对象时的404 或错误输入数据的400。
    • 但是异常代价高昂,而且您的方法签名与您的 API 没有任何关系(相反,当没有其他信息存在时,API 浏览器会从它们那里收集信息)。 Web API 的一个(我认为是不可避免的)缺点是路由概念、HTTP 层和 OOP 以一种并不总是有意义的方式结合在一起。然而,在仍然使用 IHttpActionResult 的情况下,有一种方法可以解决这个问题。这是ResponseTypeAttribute
    • 与某些事情相比,例外只是代价高昂。当您考虑将给定请求连接到控制器代码,然后将结果转换为响应所需的所有反射和 I/O 时,抛出和捕获异常所增加的开销是相当合理的。
    • 从语义的角度来看,我仍然不会认为大多数状态代码是“例外”。例如404 应该是预期的。我同意一个对象提供了一个更具体的 API。就我个人而言,我觉得泛型将有助于最好地描述 api IHttpActionResult&lt;IEnumerable&lt;Client&gt;&gt;
    猜你喜欢
    • 2014-06-05
    • 1970-01-01
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2018-06-26
    相关资源
    最近更新 更多