C# 基于Accept标头的ASP.NET核心web api操作选择
我想根据请求的accept头为同一特性(一个实体列表)返回两个不同格式的响应,分别用于“json”和“html”请求 asp.net核心是否支持根据请求中的接受标头为同一路由选择不同的操作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
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
匹配的格式化程序