最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ASP.NET Core 中的 IActionResult深度解析

 更新時(shí)間:2026年05月20日 09:07:44   作者:無(wú)風(fēng)聽(tīng)海  
文章介紹了IActionResult在ASP.NET Core中的作用及實(shí)現(xiàn)細(xì)節(jié),它用于封裝將結(jié)果寫入HTTP響應(yīng)的邏輯,并詳細(xì)描述了各種返回方式、管道執(zhí)行流程以及與IResult的區(qū)別,針對(duì)不同場(chǎng)景提供了選擇建議,感興趣的朋友跟隨小編一起看看吧

一、從一個(gè)問(wèn)題開(kāi)始

你寫了一個(gè) Web API,有時(shí)候要返回?cái)?shù)據(jù),有時(shí)候要返回 404,有時(shí)候要返回 400——這三種情況的返回值類型完全不同,一個(gè) C# 方法怎么能同時(shí)返回多種東西?

這就是 IActionResult 存在的根本原因。它的本質(zhì)是:封裝"如何把結(jié)果寫入 HTTP 響應(yīng)"的邏輯的統(tǒng)一抽象。

二、類型層次結(jié)構(gòu)

IActionResult(接口)
    └── ActionResult(抽象類,默認(rèn)實(shí)現(xiàn))
            ├── StatusCodeResult
            │       ├── NotFoundResult (404)
            │       ├── OkResult (200)
            │       └── BadRequestResult (400) ...
            ├── ObjectResult(帶 Body,最復(fù)雜)
            │       ├── OkObjectResult (200)
            │       ├── NotFoundObjectResult (404)
            │       ├── BadRequestObjectResult (400)
            │       ├── CreatedResult (201)
            │       └── CreatedAtActionResult (201) ...
            ├── ContentResult
            ├── JsonResult
            ├── FileResult
            ├── RedirectResult
            └── ViewResult ...

你調(diào)用 Ok()、NotFound()、BadRequest() 返回的都是 ObjectResultStatusCodeResult 的子類,它們最終都實(shí)現(xiàn)了 IActionResult 接口。

三、核心方法簽名逐層拆解

層一:IActionResult 接口

定義在 Microsoft.AspNetCore.Mvc.Abstractions.dll,整個(gè)接口只有一個(gè)方法:

// 命名空間: Microsoft.AspNetCore.Mvc
public interface IActionResult
{
    // 由 MVC 框架調(diào)用,用于處理 Action 方法的返回結(jié)果
    Task ExecuteResultAsync(ActionContext context);
}

ActionContext 攜帶了執(zhí)行結(jié)果所需的全部上下文:

public class ActionContext
{
    public HttpContext          HttpContext       { get; }  // 整個(gè) HTTP 請(qǐng)求/響應(yīng)
    public RouteData            RouteData         { get; }  // 路由數(shù)據(jù)
    public ActionDescriptor     ActionDescriptor  { get; }  // Action 的元數(shù)據(jù)
    public ModelStateDictionary ModelState        { get; }  // 模型驗(yàn)證狀態(tài)
}

層二:ActionResult 抽象類

定義在 Microsoft.AspNetCore.Mvc.Core.dll,是整個(gè)體系的基礎(chǔ):

public abstract class ActionResult : IActionResult
{
    // 同步版本(供簡(jiǎn)單場(chǎng)景使用,子類可選擇重寫)
    public virtual void ExecuteResult(ActionContext context) { }
    // 異步版本:默認(rèn)實(shí)現(xiàn)調(diào)用同步方法,再返回 Task.CompletedTask
    // 需要真正異步 I/O 的子類(如寫文件流)應(yīng)直接重寫此方法
    public virtual Task ExecuteResultAsync(ActionContext context)
    {
        ExecuteResult(context);
        return Task.CompletedTask;
    }
}

關(guān)鍵設(shè)計(jì): 默認(rèn)實(shí)現(xiàn)把異步路由到同步。子類按需選擇重寫哪一個(gè)——邏輯簡(jiǎn)單的重寫同步 ExecuteResult,有 I/O 操作的重寫異步 ExecuteResultAsync。

層三:StatusCodeResult(無(wú) Body 的結(jié)果)

public class StatusCodeResult : ActionResult, IStatusCodeActionResult
{
    public int StatusCode { get; }
    public StatusCodeResult(int statusCode) { StatusCode = statusCode; }
    // 重寫同步方法,邏輯極簡(jiǎn):只設(shè)置狀態(tài)碼
    public override void ExecuteResult(ActionContext context)
    {
        context.HttpContext.Response.StatusCode = StatusCode;
    }
}
// 子類只做一件事:傳入固定的狀態(tài)碼
public class NotFoundResult : StatusCodeResult
{
    public NotFoundResult() : base(StatusCodes.Status404NotFound) { }
}
public class OkResult : StatusCodeResult
{
    public OkResult() : base(StatusCodes.Status200OK) { }
}

層四:ObjectResult(帶 Body 的結(jié)果,最復(fù)雜)

public class ObjectResult : ActionResult, IStatusCodeActionResult
{
    public object?   Value        { get; set; }  // 要序列化的對(duì)象
    public int?      StatusCode   { get; set; }  // HTTP 狀態(tài)碼(可空)
    public MediaTypeCollection ContentTypes { get; set; }
    public FormatterCollection<IOutputFormatter> Formatters { get; set; }
    // 重寫異步版本(序列化寫流是 I/O 操作)
    public override async Task ExecuteResultAsync(ActionContext context)
    {
        // 子類在序列化前可修改狀態(tài)(如設(shè)置 StatusCode、寫 Header)
        OnFormatting(context);
        // 委托給 ObjectResultExecutor,它負(fù)責(zé):
        // 1. 內(nèi)容協(xié)商:根據(jù) Accept 頭選擇 Formatter
        // 2. 調(diào)用 IOutputFormatter 序列化 Value
        // 3. 設(shè)置 Content-Type 和 StatusCode
        var executor = context.HttpContext.RequestServices
            .GetRequiredService<IActionResultExecutor<ObjectResult>>();
        await executor.ExecuteAsync(context, this);
    }
    public virtual void OnFormatting(ActionContext context) { }
}

所有"帶 Body"的子類只做一件事——在構(gòu)造函數(shù)里設(shè)置狀態(tài)碼,其余邏輯全部繼承自 ObjectResult

public class OkObjectResult : ObjectResult
{
    public OkObjectResult(object? value) : base(value)
    { StatusCode = StatusCodes.Status200OK; }
}
// CreatedAtActionResult 更特殊:重寫了 OnFormatting 來(lái)設(shè)置 Location Header
public class CreatedAtActionResult : ObjectResult
{
    public string? ActionName     { get; set; }
    public string? ControllerName { get; set; }
    public object? RouteValues    { get; set; }
    public override void OnFormatting(ActionContext context)
    {
        var url = urlHelper.Action(ActionName, ControllerName, RouteValues);
        context.HttpContext.Response.Headers[HeaderNames.Location] = url;
    }
}

四、四種返回方式全景

1. 具體類型(最簡(jiǎn)單)

結(jié)果固定、無(wú)分支時(shí)使用:

[HttpGet]
public Task<List<Product>> Get() =>
    _db.Products.OrderBy(p => p.Name).ToListAsync();

2. IActionResult(靈活,需手動(dòng)標(biāo)注 Swagger 文檔)

當(dāng)一個(gè) Action 存在多種 HTTP 狀態(tài)碼分支時(shí)使用:

[HttpGet("{id}")]
[ProducesResponseType<Product>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
    var product = _db.Products.Find(id);
    return product == null ? NotFound() : Ok(product);
}

3. ActionResult(現(xiàn)代推薦寫法)

兩大優(yōu)勢(shì):[ProducesResponseType]Type 屬性可從泛型參數(shù)自動(dòng)推斷;支持直接 return T 而無(wú)需手動(dòng) Ok(T)

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
    var product = _db.Products.Find(id);
    // 直接 return product,隱式轉(zhuǎn)換自動(dòng)包裝成 OkObjectResult
    return product == null ? NotFound() : product;
}

常見(jiàn)陷阱: C# 不支持接口的隱式轉(zhuǎn)換。當(dāng)泛型參數(shù)是接口(如 IEnumerable<Product>)時(shí),必須調(diào)用 .ToList() 轉(zhuǎn)為具體類型才能編譯通過(guò)。

4. Results<T1, T2>(跨場(chǎng)景共享,編譯期類型安全)

可省略所有 [ProducesResponseType],且框架會(huì)在編譯期檢查返回值是否合法:

[HttpGet("{id}")]
public Results<NotFound, Ok<Product>> GetById(int id)
{
    var product = _db.Products.Find(id);
    return product == null
        ? TypedResults.NotFound()
        : TypedResults.Ok(product);
    // 返回其他類型 → 編譯錯(cuò)誤!
}

五、管道執(zhí)行流程

HTTP 請(qǐng)求
    │
    ▼
中間件管道(UseRouting → UseAuthentication → UseEndpoints)
    │
    ▼
ControllerActionInvoker(核心調(diào)度器)
    │
    ├─── [1] Authorization Filter ──────────── OnAuthorizationAsync
    │          不通過(guò) → 直接短路,寫入 401/403
    │
    ├─── [2] Resource Filter ────────────────── OnResourceExecutingAsync
    │          可短路(如緩存命中直接返回)
    │
    ├─── [3] Model Binding
    │          綁定 Action 參數(shù);[ApiController] 時(shí)驗(yàn)證失敗自動(dòng)返回 400
    │
    ├─── [4] Action Filter Before ───────────── OnActionExecutingAsync
    │          可修改參數(shù),或設(shè)置 context.Result 短路
    │
    ├─── ★★★ [5] 執(zhí)行 Action 方法本體 ★★★
    │          return Ok(product)
    │          → 創(chuàng)建 OkObjectResult 對(duì)象,此時(shí)【尚未寫入任何響應(yīng)】
    │
    ├─── [6] Action Filter After ────────────── OnActionExecutedAsync
    │          可攔截并替換 context.Result
    │
    ├─── [7] Exception Filter
    │          處理未被捕獲的異常
    │
    ├─── [8] Result Filter Before ───────────── OnResultExecutingAsync
    │          寫響應(yīng)前最后處理(如追加響應(yīng) Header)
    │
    ├─── ★★★ [9] result.ExecuteResultAsync(actionContext) ★★★
    │          真正把狀態(tài)碼、Header、Body 寫入 HttpResponse
    │
    └─── [10] Result Filter After + Resource Filter After
               OnResultExecutedAsync / OnResourceExecutedAsync
    │
    ▼
HTTP 響應(yīng)返回客戶端

最關(guān)鍵的一點(diǎn): return Ok(product) 并不立即寫響應(yīng)。它只是創(chuàng)建了一個(gè) OkObjectResult 對(duì)象。真正的 HTTP 響應(yīng)寫入,發(fā)生在第 9 步——框架調(diào)用 ExecuteResultAsync 的時(shí)候。

六、一次 return Ok( product ) 的完整內(nèi)部旅程

public IActionResult GetById(int id)
{
    var product = _db.Products.Find(id);
    return product == null ? NotFound() : Ok(product);
}

假設(shè) product 存在,展開(kāi)每一步:

[步驟 1] ControllerBase.Ok(product)
         → new OkObjectResult(product)
            StatusCode = 200, Value = product 對(duì)象(內(nèi)存中的 C# 對(duì)象)
[步驟 2] Action 方法返回,ControllerActionInvoker 拿到 OkObjectResult
         經(jīng)過(guò) Action Filter (OnActionExecuted)
         經(jīng)過(guò) Result Filter (OnResultExecuting)
[步驟 3] 框架調(diào)用:
         await result.ExecuteResultAsync(actionContext)
[步驟 4] ObjectResult.ExecuteResultAsync 內(nèi)部:
         OnFormatting(context)    // OkObjectResult 確認(rèn) StatusCode = 200
         var executor = services.GetRequiredService<IActionResultExecutor<ObjectResult>>()
         await executor.ExecuteAsync(context, this)
[步驟 5] ObjectResultExecutor.ExecuteAsync 內(nèi)部:
         a. 內(nèi)容協(xié)商:檢查請(qǐng)求 Accept 頭(application/json? application/xml?)
         b. 從 IOutputFormatter 列表中選擇匹配的 Formatter
            → 默認(rèn)是 SystemTextJsonOutputFormatter
         c. Response.StatusCode = 200
         d. Response.ContentType = "application/json; charset=utf-8"
         e. formatter.WriteAsync(context)
            → 將 product 序列化為 JSON,寫入 Response.Body 流

OkObjectResult 并沒(méi)有自己實(shí)現(xiàn)序列化邏輯——它把一切都交給父類 ObjectResult,ObjectResult 再把內(nèi)容協(xié)商和序列化交給 ObjectResultExecutor。這是典型的職責(zé)分離:Result 對(duì)象只描述"要返回什么",Executor 負(fù)責(zé)"如何寫入"。

七、IActionResult vs IResult:兩套體系的本質(zhì)差異

// MVC 體系(Microsoft.AspNetCore.Mvc)
public interface IActionResult
{
    Task ExecuteResultAsync(ActionContext context);  // 參數(shù)是 ActionContext
}
// Minimal API 體系(Microsoft.AspNetCore.Http)
public interface IResult
{
    Task ExecuteAsync(HttpContext httpContext);       // 參數(shù)是 HttpContext,更輕量
}
對(duì)比項(xiàng)IActionResult(MVC)IResult(Minimal API)
接口方法ExecuteResultAsyncExecuteAsync
參數(shù)類型ActionContextHttpContext
調(diào)用方ControllerActionInvokerRequestDelegateFactory
內(nèi)容協(xié)商? 支持(IOutputFormatter)? 不支持
序列化可插拔 Formatter(JSON/XML/自定義)固定(WriteAsJsonAsync)
Filter 管道? 完整管道? 僅 EndpointFilter
適用場(chǎng)景傳統(tǒng) MVC / Web API ControllerMinimal API / 跨場(chǎng)景共享

IResult 的實(shí)現(xiàn)極其直接,以 Ok<T> 為例:

// Microsoft.AspNetCore.Http.HttpResults.Ok<TValue>
public sealed class Ok<TValue> : IResult, IStatusCodeHttpResult
{
    public int?    StatusCode => 200;
    public TValue? Value { get; }
    // 沒(méi)有 Formatter,沒(méi)有內(nèi)容協(xié)商,直接寫流
    public async Task ExecuteAsync(HttpContext httpContext)
    {
        httpContext.Response.StatusCode = 200;
        if (Value is not null)
            await httpContext.Response.WriteAsJsonAsync(Value);
    }
}

八、常用 ActionResult 速查

便捷方法狀態(tài)碼對(duì)應(yīng)類有 Body
Ok(data)200OkObjectResult?
Ok()200OkResult
Created(uri, data)201CreatedResult? + Location
CreatedAtAction(...)201CreatedAtActionResult? + Location
NoContent()204NoContentResult
BadRequest()400BadRequestResult
BadRequest(error)400BadRequestObjectResult?
Unauthorized()401UnauthorizedResult
Forbid()403ForbidResult
NotFound()404NotFoundResult
NotFound(data)404NotFoundObjectResult?
Conflict()409ConflictResult
StatusCode(code)自定義StatusCodeResult
Content("text")200ContentResult? text/plain

九、選型決策流程

需要返回多種 HTTP 狀態(tài)?
├── 否 ──→ 直接返回具體類型(最簡(jiǎn)單)
└── 是
    │
    ├── 需要內(nèi)容協(xié)商或自定義 Formatter?
    │       └── 是 ──→ ActionResult<T>(MVC 場(chǎng)景首選)
    │
    └── 需要和 Minimal API 共享代碼?
            ├── 是 ──→ Results<T1, T2>(編譯期類型安全,自動(dòng)推斷文檔)
            └── 否 ──→ ActionResult<T>(現(xiàn)代 .NET 推薦寫法)

一句話總結(jié): 新項(xiàng)目首選 ActionResult<T>,既有類型安全,又有 Swagger 文檔自動(dòng)推斷;需要跨 Minimal API 共享邏輯時(shí)換 Results<T1, T2>。刪除 Action 成功時(shí)無(wú)數(shù)據(jù)可返回,用 IActionResult 配合 NoContent() 更語(yǔ)義清晰。

到此這篇關(guān)于ASP.NET Core 中的 IActionResult深度解析的文章就介紹到這了,更多相關(guān)ASP.NET Core IActionResult內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 談?wù)?net對(duì)象生命周期(垃圾回收)

    談?wù)?net對(duì)象生命周期(垃圾回收)

    這篇文章主要介紹了談?wù)?net對(duì)象生命周期(垃圾回收),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Linux上使用Docker部署ASP.NET?Core應(yīng)用程序

    Linux上使用Docker部署ASP.NET?Core應(yīng)用程序

    這篇文章介紹了使用Docker部署ASP.NET?Core應(yīng)用程序的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • 概述.net開(kāi)發(fā)過(guò)程中Bin目錄下面幾種文件格式

    概述.net開(kāi)發(fā)過(guò)程中Bin目錄下面幾種文件格式

    本篇文章主要對(duì)項(xiàng)目發(fā)布的時(shí)候,經(jīng)常用到的幾個(gè)文件:.pdb、.xsd、.vshost.exe、.exe、.exe.config、.vshost.exe.config的作用進(jìn)行介紹,具有一定的參考價(jià)值,需要的朋友可以看下
    2016-12-12
  • Mvc動(dòng)態(tài)注冊(cè)HttpModule詳解

    Mvc動(dòng)態(tài)注冊(cè)HttpModule詳解

    本文主要介紹了Mvc動(dòng)態(tài)注冊(cè)HttpModule的方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-03-03
  • ASP.NET?MVC5網(wǎng)站開(kāi)發(fā)顯示文章列表(九)

    ASP.NET?MVC5網(wǎng)站開(kāi)發(fā)顯示文章列表(九)

    顯示文章列表分兩塊,管理員可以顯示全部文章列表,一般用戶只顯示自己的文章列表。文章列表的顯示采用easyui-datagrid,后臺(tái)需要與之對(duì)應(yīng)的action返回json類型數(shù)據(jù),感興趣的小伙伴們可以參考一下
    2015-09-09
  • .NET Core3.0 日志 logging的實(shí)現(xiàn)

    .NET Core3.0 日志 logging的實(shí)現(xiàn)

    這篇文章主要介紹了.NET Core3.0 日志 logging的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • .NET Core3.1編寫混合C++程序

    .NET Core3.1編寫混合C++程序

    這篇文章主要介紹了.NET Core3.1編寫混合C++程序,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • asp.net 冒泡算法的理解

    asp.net 冒泡算法的理解

    您真的理解冒泡排序嗎?還是背下來(lái)了呢?冒泡排序真的只有一種方法嗎?
    2010-05-05
  • ASPNET按鈕只執(zhí)行客戶端代碼不回送頁(yè)面實(shí)現(xiàn)思路

    ASPNET按鈕只執(zhí)行客戶端代碼不回送頁(yè)面實(shí)現(xiàn)思路

    有些時(shí)候需要實(shí)現(xiàn)只執(zhí)行客戶端代碼不回送頁(yè)面,不過(guò)很多童鞋們不清楚如何實(shí)現(xiàn)呢,還好本文的出現(xiàn)將解決你的困擾,感興趣的朋友可以了解下,或許對(duì)你有所幫助
    2013-02-02
  • ASP.NET(C#)驗(yàn)證數(shù)字的兩種方法

    ASP.NET(C#)驗(yàn)證數(shù)字的兩種方法

    ASP.NET(C#)驗(yàn)證數(shù)字的兩種方法,需要的朋友可以參考一下
    2013-06-06

最新評(píng)論

高密市| 华蓥市| 仁寿县| 怀仁县| 屯留县| 巴彦淖尔市| 方正县| 张家界市| 长岭县| 乌拉特中旗| 洛隆县| 上林县| 隆子县| 鄂州市| 吉隆县| 宁强县| 瑞昌市| 北川| 六枝特区| 通城县| 通许县| 秦皇岛市| 淮北市| 阿拉善左旗| 宁阳县| 灵台县| 四川省| 和静县| 延寿县| 郧西县| 平阴县| 德阳市| 于都县| 资阳市| 赤水市| 泰安市| 于田县| 巴楚县| 禄丰县| 开阳县| 诸暨市|