В настоящее время я конвертирую библиотеку ASP. NET в ASP. NET Ядро, которое сильно связано с привязкой к модели, и одну проблему, которую я не могу решить, это то, что для случаев, когда требуется привязка к модели чтобы попытаться получить значения через провайдеров значений как из (From) Query, так и (From) Route (так как они имеют разные BindingSource), он может получить доступ только к одному, что приводит к сбою привязки, так как не удается найти целевое значение.
При отладке приложения я вижу, что ModelBindingContext имеет обоих провайдеров значений в своем частном OriginalValueProvider, но при попытке доступа к ValueProvider он возвращает только одного из провайдеров - в этом случае только QueryStringValueProvider, а не RouteValueProvider).
Похоже, что это не было обычным поведением ASP. NET, поскольку там существующее приложение с радостью использует обоих провайдеров значений для поиска своего значения - и делает это успешно. Это какое-то существенное изменение между System.Web.Http.ModelBinding -> Microsoft.AspNetCore. Mvc .ModelBinding? Есть ли какая-то опция, которая должна быть включена? Хотелось бы получить некоторые рекомендации.
Ниже приведены некоторые ограничения экрана из моей отладки:
System.Web.Http original:
Microsoft .AspNetCore. Mvc переделка:
Microsoft.AspNetCore. Mvc ОригиналValueProvider (s) подтверждение:
Редактировать: И здесь следует несколько фрагментов кода в соответствии с запросом:
Контроллер:
[HttpGet]
[Route("accounts/{accountId}/catalogs/{catalogId}/medias", Name = "GetCatalogMedias")]
[ProducesResponseType(typeof(IList<MediaResponse>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetCatalogMedias(
[FromRoute] string accountId,
[FromRoute] string catalogId,
[FromQuery, SortingFieldDefaultValue("created", SortingDirection.Desc)] IEnumerable<SortingField> sort,
[FromQuery] QueryTree<MediaResponse> q = null,
[FromQuery, Range(0, int.MaxValue)] int offset = 0,
[FromQuery, Range(1, 200)] int limit = 200)
{
if (!ModelState.IsValid)
{
return await _responseFactory.CreateBadRequest(ModelState);
}
Binder:
public class CatalogMediasQueryModelBinder<T> : BaseBinder, IModelBinder
{
private readonly QueryModelBinder _queryModelBinder;
public CatalogMediasQueryModelBinder(QueryModelBinder queryModelBinder)
{
_queryModelBinder = queryModelBinder;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var success = TryGetValueProviderResult(bindingContext, out var catalogId, "catalogId");
if (!success)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Missing catalogId");
return;
}
//...
Base Binder:
public class BaseBinder
{
protected bool TryGetValueProviderResult(ModelBindingContext bindingContext, out string result, string findValue = null)
{
if (bindingContext?.ValueProvider == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
result = null;
var modelName = findValue ?? bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return false;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
if (string.IsNullOrWhiteSpace(value))
{
return false;
}
result = value;
return true;
}
protected Task SetModelBindingResult<T>(ModelBindingContext bindingContext, T value)
{
bindingContext.Result = ModelBindingResult.Success(value);
return Task.CompletedTask;
}
}