Наличие атрибута [ApiController]
вводит Вывод параметра источника привязки для параметров действия. При запуске соглашение модели действия выполняется для всех обнаруженных действий контроллера и определяет источники привязки. Для сложных типов, таких как ваши параметры Guid[]
и UserToken
, этот вывод выбирает тело запроса в качестве источника - как если бы вы добавили [FromBody]
к обоим этих параметров самостоятельно, например, это:
public Task<ActionResult> SomeAction(
[FromBody] Guid[] ids,
[FromBody] UserToken userToken,
CancellationToken cancellationToken)
В своем вопросе вы утверждаете:
Кажется, что MVC игнорирует пользовательское связующее, которое у меня есть для типа UserToken, и пытается связать его, используя методы по умолчанию.
Это не совсем то, что здесь происходит. Он еще ничего не пытается связать - он просто пытается настроить источники привязки при запуске, прежде чем может произойти привязка модели. Вы правильно проинструктировали MVC использовать ваше пользовательское связующее для модели, но упомянутое выше соглашение о модели действия ничего не знает о добавленном вами IModelBinderProvider
. Даже если это так, фактическая связь между поставщиком связывателя модели и типом (UserToken
) не известна до тех пор, пока не будет запущен метод GetBinder
, что происходит только тогда, когда необходимо связывание модели; не запускается при настройке модели приложения.
Если вы обновите свой класс UserToken
, добавив атрибут [ModelBinder]
, все будет работать (вы даже можете удалить UserTokenBinderProvider
):
[ModelBinder(typeof(UserTokenBinderProvider))]
public class UserToken { }
Большим недостатком этого подхода является то, что ваш класс UserToken
будет зависеть от атрибута MVC, который может оказаться не тем, что вам нужно. Итак, есть что-то лучше?
Теперь вам может быть интересно, почему я не показал [FromBody]
для параметра CancellationToken
выше. Значит ли это, что CancellationToken
получает специальное лечение? Да, это . BindingSourceMetadataProvider
добавляется к экземпляру MvcOptions
, который указывает его источник привязки как BindingSource.Special
. Когда соглашение модели действия выполняется и пытается определить источник привязки, он видит, что источник привязки уже установлен, и оставляет его в покое .
Чтобы решить вашу проблему, добавьте BindingSourceMetadataProvider
для вашего UserToken
типа и используйте BindingSource.Special
, например:
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new UserTokenBinderProvider());
options.ModelMetadataDetailsProviders.Add(
new BindingSourceMetadataProvider(typeof(UserToken), BindingSource.Special));
});