【问题标题】:ASP.NET Core MVC - Return ViewResult or JSON from controller actionASP.NET Core MVC - 从控制器操作返回 ViewResult 或 JSON
【发布时间】:2020-06-13 00:20:56
【问题描述】:

我正在尝试使用 ASP.NET Core MVC 来实现一些目标,这似乎应该是微不足道的,但从我的研究来看,这似乎不是一件容易的事。

我想从单个端点返回 ViewResult 和 JSON(可能还有其他格式,但我暂时保持简单)。理想情况下,我返回 ViewResult 还是 JSON 将基于内置的内容协商。

当然可以简单地检查控制器内部的接受标头,如果请求 HTML,则返回 ViewResult,否则返回 JSON 结果,但随着端点数量和支持的格式的增加,这将是愚蠢的。

我认为使用自定义中间件可以做到这一点,我可以简单地等待端点的响应,检查用户代理请求的接受标头是什么,然后将结果包装在 ViewResult 或 JSONResult 中。这是理想的解决方案,因为它适用于所有端点并节省大量代码重复,但似乎不可能。

我的总体目标是以这样一种方式设置我的端点,即用户可以在浏览器中或通过邮递员使用完全相同的端点,并且他们将获得他们期望的响应格式,即 HTML 或 JSON。有没有人能够以不需要 hacky 解决方案的方式实现这一结果?

【问题讨论】:

  • 明确地说,您是否要添加一个中间件,以便您可以根据请求的数据类型返回响应?如果您想要一个中间件,那么以下链接可能会有所帮助:stackoverflow.com/questions/37395227/…
  • 您实际上是指 HTML 而不是 XML?从一个控制器操作支持 JSON 和 HTML 似乎令人困惑,因为一种是纯数据格式,另一种是更“表示感知”的格式。如果不是 XML,您能否以 JSON 和 HTML 格式显示示例响应?
  • 明确地说,是的,我想返回特定端点的 HTML(而不是 XML)表示,同时还允许消费者返回 JSON 表示。如果您想象一个端点返回一个项目列表,那么在浏览器中访问该端点的用户会看到带有 CSS 等的 HTML,但是那些简单地通过邮递员或您有什么请求数据的用户将获得这些项目的 JSON 数据结构.我认为这是完全可行的,即使不是更好的 API 设计方式。
  • 这里是一个 github 问题的链接,它更深入地讨论了这个问题。 github.com/dotnet/aspnetcore/issues/3891

标签: c# asp.net-mvc asp.net-core


【解决方案1】:

你可以实现MVC Action filter来轻松实现这样的功能。

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Net.Http.Headers;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ViewJsonActionFilterAttribute : Attribute, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        //result must be OkObjectResult
        if (context.Result is OkObjectResult okResult)
        {
            var accept = context.HttpContext.Request.Headers[HeaderNames.Accept];
            switch (accept)
            {
                //changing result to ViewResult
                case "text/html":
                    var controller = (Controller)context.Controller;
                    context.Result = controller.View(okResult.Value);
                    break;
                case "application/json":
                default:
                    //do nothing
                    break;
            }
        }
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        //do nothing
    }
}

然后将该属性应用于特定的动作/控制器或全局。始终从控制器返回 Ok 作为成功结果,以便过滤器可以按预期处理它。

//important: controller should be derived from Controller class to contain View method
public class TestController : Controller
{
    [HttpGet]
    [ViewJsonActionFilter]
    public IActionResult TestViewJson()
    {
        var model = new ViewJsonTestViewModel
        {
            Id = 55,
            Name = "I'm a test model"
        };

        return Ok(model);
    }
}

如果你将请求Accept 标头设置为text/html 你会得到html,否则它会返回json。

【讨论】:

  • 这看起来很有趣,似乎与我的想法一致。
猜你喜欢
  • 2010-09-18
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多