如何在 asp.net core 中编写自定义 actionResult

Posted

技术标签:

【中文标题】如何在 asp.net core 中编写自定义 actionResult【英文标题】:How to write custom actionResult in asp.net core 【发布时间】:2021-01-26 21:15:45 【问题描述】:

在 webApi2 中,我可以通过继承 IHttpActionResult 来编写自定义 ActionResult。

示例:

public class MenivaActionResult : IHttpActionResult
    
        private readonly HttpRequestMessage _request;
        private readonly ServiceResponseBase _response;

        public MenivaActionResult(HttpRequestMessage request, ServiceResponseBase response)
        
            _request = request;
            _response = response;
        


        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken token)
        

            HttpResponseMessage httpresponseMessage = _response.Exception != null
                ? _request.CreateErrorResponse((HttpStatusCode)_response.HttpCode,
                    _response.Exception.Message+":"+_response.Exception.HelpCode)
                : _request.CreateResponse((HttpStatusCode)_response.HttpCode, _response.Data);
            return Task.FromResult(httpresponseMessage);
        
    

ServiceResponseBase 类对象包含来自服务层的所有异常和数据..

如何将此代码移植到 asp.net 核心。我试过了,但我不知道如何从 .net 核心中的 HttpRequestMessage 对象创建响应消息。 IActionResult 只有Task ExecuteResultAsync(ActionContext context) 方法。我如何修改此方法的响应

【问题讨论】:

【参考方案1】:

这是一个例子:

public class TestResult

    public Exception Exception  get; set; 
    public object Data  get; set; 


public class TestActionResult : IActionResult

    private readonly TestResult _result;

    public TestActionResult(TestResult result)
    
        _result = result;
    

    public async Task ExecuteResultAsync(ActionContext context)
    
        var objectResult = new ObjectResult(_result.Exception ?? _result.Data)
        
            StatusCode = _result.Exception != null
                ? StatusCodes.Status500InternalServerError
                : StatusCodes.Status200OK
        ;

        await objectResult.ExecuteResultAsync(context);
    

ObjectResult 是当您从操作返回非IActionResult 时转换结果的类型。它将为您进行内容协商。

您也可以从ObjectResult 继承并设置要写入构造函数的状态码和数据。

更多关于 ASP.NET Core 中的内容协商:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/formatting#content-negotiation

【讨论】:

但是我需要传递对象而不是简单的字符串,我需要使用默认的内容协商功能,因此无法将对象转换为任何形式的字符串表示形式,如 json 或 xml。 _request.CreateResponse((HttpStatusCode)_response.HttpCode, _response.Data);我的 webapi2 中的这一行会自动协商数据 @BinsonEldhose 查看我更新的示例。那将是ObjectResult 的工作。 很好的例子,但是像这样的自定义操作结果的文件夹结构呢? 你的意思是这个类的文件夹名称应该是什么?这取决于您和您的团队 :) 我通常使用 Results 文件夹。 如何对 TestActionResult 进行单元测试?我很想确保 ActionContext 被模拟并断言预期的结果;【参考方案2】:

尽管@juunas 的回答在技术上是正确的,但您真正尝试实现的是自定义错误处理。更好的方法是使用动作过滤器、中间件过滤器或单独的中间件来解耦这个逻辑(取决于你要覆盖什么范围)。

主要思想是控制器不应该负责处理异常。它应该返回具有 OK 状态的预期结果,或者说有问题(抛出异常)并委托给管道的其他部分来处理问题。

查看 SO:Error handling in ASP.NET Core 1.0 Web API (Sending ex.Message to the client) 示例。 Error Handling in ASP.NET Core doc 也可能有用。

【讨论】:

当然,您可以使用异常过滤器来实现同样的目的。【参考方案3】:

为什么不直接使用 StatusCode 方法呢?像这样的例子:

public async Task<IActionResult> ExamleEndpoint()

    // ... some code here which concatenates result string and selects a status code
    var statusCode = HttpStatusCode.OK;
    var message = "Some string response here but StatusCode also accepts Object value";
    return StatusCode((int) statusCode, message);

【讨论】:

以上是关于如何在 asp.net core 中编写自定义 actionResult的主要内容,如果未能解决你的问题,请参考以下文章