C# 基于Accept标头的ASP.NET核心web api操作选择

C# 基于Accept标头的ASP.NET核心web api操作选择,c#,asp.net-core,asp.net-core-mvc,asp.net-core-webapi,C#,Asp.net Core,Asp.net Core Mvc,Asp.net Core Webapi,我想根据请求的accept头为同一特性(一个实体列表)返回两个不同格式的响应,分别用于“json”和“html”请求 asp.net核心是否支持根据请求中的接受标头为同一路由选择不同的操作 if(Request.Headers["Content-Type"] == "application/json") { return OK(json); } else { return View(); } 没关系吧?我深入到.net核心源代码中,寻找其他具有类似行为的属性,例如Microso

我想根据请求的accept头为同一特性(一个实体列表)返回两个不同格式的响应,分别用于“json”和“html”请求

asp.net核心是否支持根据请求中的接受标头为同一路由选择不同的操作

if(Request.Headers["Content-Type"] == "application/json")
{
    return OK(json);
}
else
{
    return View();
}

没关系吧?

我深入到.net核心源代码中,寻找其他具有类似行为的属性,例如
Microsoft.AspNetCore.Mvc.HttpGet
Microsoft.AspNetCore.Mvc.ProducesAttribute
。 这两个属性都实现了一个
Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint
接口,AspNetCore.Mvc使用该接口控制控制器内动作的选择

因此,我实现了一个简化的ProducesAttribute(“贡”)来检查accept头

    /// <summary>
    /// A filter that specifies the supported response content types. The request accept header is used to determine if it is a valid action
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class AcceptHeaderAttribute : Attribute, IActionConstraint
    {

        public AcceptHeaderAttribute(string contentType, params string[] otherContentTypes)
        {            
            if (contentType == null)
                throw new ArgumentNullException(nameof(contentType));

            // We want to ensure that the given provided content types are valid values, so
            // we validate them using the semantics of MediaTypeHeaderValue.
            MediaTypeHeaderValue.Parse(contentType);

            for (var i = 0; i < otherContentTypes.Length; i++)
            {
                MediaTypeHeaderValue.Parse(otherContentTypes[i]);
            }

            ContentTypes = GetContentTypes(contentType, otherContentTypes);
        }

        public MediaTypeCollection ContentTypes
        {
            get; set;
        }

        public int Order
        {
            get
            {
                return 0;
            }
        }

        private bool IsSubsetOfAnyContentType(string requestMediaType)
        {
            var parsedRequestMediaType = new MediaType(requestMediaType);
            for (var i = 0; i < ContentTypes.Count; i++)
            {
                var contentTypeMediaType = new MediaType(ContentTypes[i]);
                if (parsedRequestMediaType.IsSubsetOf(contentTypeMediaType))
                {
                    return true;
                }
            }
            return false;
        }

        public bool Accept(ActionConstraintContext context)
        {
            var requestAccept = context.RouteContext.HttpContext.Request.Headers[HeaderNames.Accept];
            if (StringValues.IsNullOrEmpty(requestAccept))
                return true;

            if (IsSubsetOfAnyContentType(requestAccept))
                return true;

            return false;
        }

        private MediaTypeCollection GetContentTypes(string firstArg, string[] args)
        {
            var completeArgs = new List<string>();
            completeArgs.Add(firstArg);
            completeArgs.AddRange(args);

            var contentTypes = new MediaTypeCollection();
            foreach (var arg in completeArgs)
            {
                contentTypes.Add(arg);
            }

            return contentTypes;
        }
    }
//
///指定支持的响应内容类型的筛选器。request accept标头用于确定该操作是否有效
/// 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple=false,Inherited=true)]
公共类AcceptHeaderAttribute:属性,IActionConstraint
{
公共AcceptHeaderAttribute(字符串contentType、参数string[]其他contentType)
{            
if(contentType==null)
抛出新ArgumentNullException(nameof(contentType));
//我们希望确保提供的给定内容类型是有效值,因此
//我们使用MediaTypeHeaderValue的语义来验证它们。
MediaTypeHeaderValue.Parse(contentType);
for(var i=0;i
可以使用此属性装饰任何操作


请注意,很容易更改并允许指定要检查的标题和值。

我需要一个操作选择器,以便使用该代码创建中间件并返回重定向到操作controller@animalitomaquina只需将
returnview()
替换为
returnfooaction()
调用,您将看到selector.ASP.NET核心已经检查了
Accept
标题,以决定使用哪个输出格式化程序。签入文档。HTML格式化程序会返回什么呢?它会使用什么标签?它应该使用一个特定的模板吗?还要查看Shawn Wildermuth关于它不仅仅是内容协商的文章,我想从一个操作返回一个视图(使用所有的viewengine/razor stuff/ModelSate)和从另一个操作返回一个json序列化,甚至(我现在还不确定)我需要不同的过滤器,或者每个操作中的授权属性。然后您应该询问MVC,而不是Web API。内容协商在那里也有效。唯一的问题是您需要检查
Accept
标题,并在请求html时使用
View()
,否则使用
Ok()
。好处是您不需要执行任何额外的配置或添加任何服务,除非您想添加更多的格式化程序,例如XML或word。使用
Ok()
可确保使用与
Accept
匹配的格式化程序