ASP.NET 核心 MVC - 从控制器操作返回视图结果或 JSON



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

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

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

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

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

您可以实现 MVC 操作筛选器来轻松实现此类功能。

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。

最新更新