如何在 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的主要内容,如果未能解决你的问题,请参考以下文章

在 Asp.net Core MVC 中定义自定义客户端验证规则

如何在 ASP.NET Core 控制器中返回自定义 HTTP 响应?

如何在 ASP.NET Core 的自定义 TagHelper 中呈现 Razor 模板?

如何在 asp.net core 2.1 中使用自定义消息设置状态代码?

如何在 ASP.NET Core 中实现自定义模型验证?

在自定义 ASP.NET Core 配置提供程序中停止 SqlDependency