C# ASP.NET核心MVC-从控制器操作返回ViewResult或JSON

C# ASP.NET核心MVC-从控制器操作返回ViewResult或JSON,c#,asp.net-mvc,asp.net-core,C#,Asp.net Mvc,Asp.net Core,我正在尝试使用ASP.NET核心MVC实现一些东西,这看起来应该很简单,但从我的研究来看,这似乎不是一项容易的任务 我想从一个端点返回ViewResult和JSON,可能还有其他格式,但现在我将保持简单。理想情况下,返回ViewResult还是JSON将基于内置内容协商 当然,如果请求HTML返回ViewResult,可以简单地检查控制器内的accept头,否则返回JSON结果,但随着端点数量和支持格式的增加,这将是愚蠢的 我假设使用自定义中间件可以做到这一点,我可以简单地等待端点的响应,检查用

我正在尝试使用ASP.NET核心MVC实现一些东西,这看起来应该很简单,但从我的研究来看,这似乎不是一项容易的任务

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

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

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

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

您可以通过实施轻松实现这一功能

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);
    }
}

如果您将request Accept header设置为text/html,您将得到html,否则它将返回json。

请澄清,是否要添加一个中间件,以便根据请求的数据类型返回响应?如果您想要一个中间件,下面的链接可能会有所帮助:您实际上是指HTML而不是XML吗?从一个控制器操作支持JSON和HTML似乎令人困惑,因为一个是纯数据格式,另一个是更关注表示的格式。如果不是XML,您能用JSON和HTML显示一个示例响应吗?要清楚,是的,我想返回特定端点的HTML而不是XML表示,同时允许使用者返回JSON表示。如果您想象一个端点返回一个项目列表,那么在浏览器中访问该端点的用户将看到带有CSS等的HTML,但是通过邮递员或其他方式请求数据的用户将获得这些项目的JSON数据结构。我认为这是完全可行的,如果不是一种更好的设计API的方法的话。这看起来很有趣,似乎符合我的想法。