リクエストのAcceptヘッダーに基づいて、同じ機能(エンティティのリスト)に対して2つの異なるフォーマットのレスポンスを返したいのですが、これは「json」と「html」リクエストに対するものです。
Asp.netコアサポートは、リクエストのAccept Headerに基づいて、同じルートに対して異なるアクションを選択しますか?
私は.netコアソースコードに飛び込んで、Microsoft.AspNetCore.Mvc.HttpGet
やMicrosoft.AspNetCore.Mvc.ProducesAttribute
などの同様の動作をする他の属性を探しました。どちらの属性もMicrosoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint
インターフェイスを実装しており、aspnetcore.mvcがコントローラー内のアクションの選択を制御するために使用します。
だから私は受け入れヘッダーをチェックするために簡略化されたProducesAttribute(「トリビュート」)を実装しました。
/// <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;
}
}
この属性を使用して、任意のアクションを装飾できます。
変更しやすく、確認するヘッダーと値を指定できることに注意してください。
if(Request.Headers["Content-Type"] == "application/json")
{
return OK(json);
}
else
{
return View();
}
それで大丈夫です?