1、前言
在之前的博客中大家可能会发现一个问题:Controller
中的方法返回值都是string
类型。其实之前只是为了演示方便,所以才统一使用string
来表示返回结果。总的来说,Controller
中的方法返回值一般分成三类:一般数据类型
、IActionResult
、ActionResult<T>
,下面开始逐一介绍。
2、一般数据类型
一般数据类型很简单,就是平时用到的int
、double
、string
、IEnumerable
等数据类型,代码如下所示:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
/// <summary>
/// 获取年龄
/// </summary>
/// <returns></returns>
[HttpGet]
public int GetAge()
{
return 20;
}
/// <summary>
/// 获取姓名
/// </summary>
/// <returns></returns>
[HttpGet]
public string GetName()
{
return "张三";
}
/// <summary>
/// 获取集合
/// </summary>
/// <returns></returns>
[HttpGet]
public IEnumerable<Person> GetPersonList()
{
return new List<Person>
{
new Person { Name = "张三", Gender = "男", Age = 25, CreateTime = DateTime.Now },
new Person { Name = "李四", Gender = "女", Age = 27, CreateTime = DateTime.Now },
new Person { Name = "王五", Gender = "男", Age = 26, CreateTime = DateTime.Now }
};
}
}
}
上面的代码看起来很不错,简洁明了、让人一眼就能看懂该方法的含义。但在实际使用过程中,它的缺陷就明显了:很难实现特殊情况下的逻辑处理。举个例子,现有如下情景:某方法接收一个int
类型的参数id
,
id>0
:返回集合id=0
:提示集合为空id<0
:提示参数错误
如果要完成上述逻辑,那我们的代码就得这么写,如下图所示:
很遗憾,上图中的代码连编译都通不过。因为方法的返回值是IEnumerable<Person>
,但实际上在代码中却返回了string
类型的变量。由此可见,一般数据类型作为方法返回值的局限性很大,
3、IActionResult类型
针对上面的问题,我们可以考虑使用IActionResult
作为返回类型。该接口主要返回的是http
的状态信息,如200
、401
、404
等。在ASP.NET Core
中,有多个类都实现了IActionResult
接口,常用的一些类如下表所示:
状态码 | 简写 | 类名 | 含义 |
---|---|---|---|
200 | Ok | OkObjectResult | 成功返回 |
201 | Created | CreatedResult | 资源被创建 |
204 | NoContent | NoContentResult | 资源存在,但不返回结果 |
400 | BadRequest | BadRequestObjectResult | 客户端一般性错误信息返回 |
401 | Unauthorized | UnauthorizedObjectResult | 未授权 |
404 | NotFound | NotFoundObjectResult | 找不到对应的信息 |
现在我们可以使用各种http
状态码来处理特殊的逻辑了,代码如下:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
public IActionResult Get(int id = 1)
{
if (id > 0)
{
return Ok(new List<Person>
{
new Person { Name = "张三", Gender = "男", Age = 25, CreateTime = DateTime.Now },
new Person { Name = "李四", Gender = "女", Age = 27, CreateTime = DateTime.Now },
new Person { Name = "王五", Gender = "男", Age = 26, CreateTime = DateTime.Now }
});
}
else if (id == 0)
{
return NotFound("找不到数据");
}
else
{
return BadRequest("错误参数");
}
}
}
}
上面的代码是简写形式,也可以写成如下形式,效果是一样的:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
public IActionResult Get(int id = 1)
{
if (id > 0)
{
return new OkObjectResult(new List<Person>
{
new Person { Name = "张三", Gender = "男", Age = 25, CreateTime = DateTime.Now },
new Person { Name = "李四", Gender = "女", Age = 27, CreateTime = DateTime.Now },
new Person { Name = "王五", Gender = "男", Age = 26, CreateTime = DateTime.Now }
});
}
else if (id == 0)
{
return new NotFoundObjectResult("找不到数据");
}
else
{
return new BadRequestObjectResult("错误参数");
}
}
}
}
当id>0
时,运行结果如下图所示:
当id=0
时,运行结果如下图所示:
当id<0
时,运行结果如下图所示:
4、ActionResult< T >类型
微软在ASP.NET Core 2.1
中引入了ActionResult<T>
类型。其实ActionResult<T>
与IActionResult
在功能上几乎没什么区别,但ActionResult<T>
类型允许将一般数据类型和http
状态信息混合使用,代码如下:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<Person>> Get(int id = 1)
{
if (id > 0)
{
return new List<Person>
{
new Person { Name = "张三", Gender = "男", Age = 25, CreateTime = DateTime.Now },
new Person { Name = "李四", Gender = "女", Age = 27, CreateTime = DateTime.Now },
new Person { Name = "王五", Gender = "男", Age = 26, CreateTime = DateTime.Now }
};
}
else if (id == 0)
{
return NotFound("找不到数据");
}
else
{
return BadRequest("错误参数");
}
}
}
}
为什么ActionResult<T>
能实现一般数据类型和http
状态信息的混用呢?按F12
导航到该类,如下图所示:
implicit operator
表明这是一个隐式转换
,即:ActionResult
可以直接转换为ActionResult<TValue>
类型。相较于IActionResult
类型只能返回http
状态信息,个人更推荐使用ActionResult
类型。
5、结语
本文主要介绍了Controller
中方法返回值问题。由于实际开发过程中的业务逻辑肯定会更加复杂,因此个人更推荐使用ActionResult<T>
作为方法返回值。