c# - 基于 Accept header 的 ASP.NET Core Web API 操作选择

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

我想根据请求的接受 header 为同一功能(实体列表)返回两个不同格式的响应,它是针对“json”和“html”请求。

asp.net core是否支持根据请求中的Accept Header为同一路由选择不同的 Action ?

最佳答案

我深入研究了 .net 核心源代码并寻找其他具有类似行为的属性,例如 Microsoft.AspNetCore.Mvc.HttpGetMicrosoft.AspNetCore.Mvc.ProducesAttribute。 这两个属性都实现了一个 Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint 接口(interface),aspnetcore.mvc 使用该接口(interface)来控制 Controller 内的 Action 选择。

所以我实现了一个简化的 ProducesAttribute(一种“致敬”)来检查接受 header 。

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

你可以用这个属性装饰任何 Action 。

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

关于c# - 基于 Accept header 的 ASP.NET Core Web API 操作选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44156625/

相关文章:

c# - 没有存储库模式的 ASP.Net MVC 和 Entity Framework 项目架构

c# - 如何将 DataTable 绑定(bind)到 Datagrid

c# - 使用类对象在 SQL 中添加申请人信息

c# - AutoMapper - 展平/展平列表

asp.net-core - 检查用户是否有权访问 Controller 操作(在访问之前)

c# - 让标签助手像 "button"一样工作 "a"

c# - 无法启动程序,访问被拒绝 C# net6.0

c# - 是否可以将 .NET Core 与 .NET Framework 一起使用

asp.net-core - ASP.NET Core 中的 Autofac 范围似乎在中间件之间有所不同

c# - .Net 核心依赖注入(inject) IdbConnection