Я создал собственный атрибут, реализующий IActionConstraint для фильтрации метода контроллера по типу носителя ввода, однако я не понимаю, почему мое ограничение не проверяется для каждого действия, а его возвращение ложно. У вас есть идея? Также кажется порядок метода в тестировании ограничений воздействия контроллера.
Спасибо за вашу помощь.
Пользовательская IActionConstraint:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
namespace CourseLibrary.API.ActionConstraints
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class RequestHeaderMatchesMediaTypeAttribute: Attribute, IActionConstraint
{
private readonly string _requestHeaderToMatch;
private readonly MediaTypeCollection _mediaTypes = new MediaTypeCollection();
public RequestHeaderMatchesMediaTypeAttribute(string requestHeaderToMatch, string mediaType, params string[] otherMediaTypes)
{
_requestHeaderToMatch = requestHeaderToMatch ?? throw new ArgumentNullException(nameof(requestHeaderToMatch));
var mediaTypes = new List<string>(){mediaType};
foreach (var otherMediaType in otherMediaTypes)
{
mediaTypes.Add(otherMediaType);
}
SetMediaTypes(mediaTypes);
}
public bool Accept(ActionConstraintContext context)
{
var headers = context.RouteContext.HttpContext.Request.Headers;
if (!headers.ContainsKey(_requestHeaderToMatch))
{
return false;
}
var parsedRequestMediaType = new MediaType(headers[_requestHeaderToMatch]);
return _mediaTypes.Select(mediaType => new MediaType(mediaType)).Contains(parsedRequestMediaType);
}
public int Order => HttpMethodActionConstraint.HttpMethodConstraintOrder + 1 ;
private void SetMediaTypes(IEnumerable<string> mediaTypes)
{
foreach (var mediaType in mediaTypes)
{
if (MediaTypeHeaderValue.TryParse(mediaType, out var parsedMediaType))
{
_mediaTypes.Add(parsedMediaType);
}
else
{
throw new ArgumentException(nameof(mediaType));
}
}
}
}
}
Контроллер:
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using CourseLibrary.API.ActionConstraints;
using CourseLibrary.API.Entities;
using CourseLibrary.API.Helpers.Extensions;
using CourseLibrary.API.Helpers.Pagination;
using CourseLibrary.API.Models;
using CourseLibrary.API.Models.Authors;
using CourseLibrary.API.ResourceParameters;
using CourseLibrary.API.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace CourseLibrary.API.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class AuthorsController : ControllerBase
{
[RequestHeaderMatchesMediaType("Content-Type",
"application/json","application/vnd.marvin.authorforcreation+json")]
[Consumes("application/json", "application/vnd.marvin.authorforcreation+json")]
[HttpPost(Name = "CreateAuthor")]
public IActionResult CreateAuthor(AuthorForCreationDto authorForCreationDto)
{
var authorForCreation = _mapper.Map<Author>(authorForCreationDto);
_courseLibraryRepository.AddAuthor(authorForCreation);
_courseLibraryRepository.Save();
var createdAuthor = _mapper.Map<AuthorDto>(authorForCreation);
var links = GetLinksForAuthor(createdAuthor.Id);
var linkedResourceToReturn = createdAuthor.ShapeData() as IDictionary<string, object>;
linkedResourceToReturn.Add("links",links);
return CreatedAtRoute("GetAuthor",new {authorId = createdAuthor.Id}, linkedResourceToReturn);
}
[RequestHeaderMatchesMediaType("Content-Type",
"application/vnd.marvin.authorforcreationwithdateofdeath+json")]
[Consumes( "application/vnd.marvin.authorforcreationwithdateofdeath+json")]
[HttpPost(Name = "CreateAuthorWithDateOfDeath")]
public IActionResult CreateAuthorWithDateOfDeath(AuthorCreationWithDateOfDeathDto authorCreationWithDateOfDeathDto)
{
return CreateAuthor(authorCreationWithDateOfDeathDto);
}
}
}