Примеры, на которые вы ссылались, чтобы использовать тип строки внешнего запроса для определения типа.
Если вы называете свое действие следующим образом : SomeAction?WhatType=YourNamespaceName.A
, привязка работает как ожидалось.
bindingContext.ModelName
быть пустым - это нормально, оно будет установлено после привязки модели. Вы можете установить его после установки bindingContext.Result, если хотите. Параметр WhatType
взят из QueryStringValueProvider
, поэтому префикс не подходит.
Как выполнить связывание абстрактной модели только на основе JSON
Для этого нам понадобится:
- Поставщик значений для чтения JSON и предоставления нам некоторого значения "WhatType" вместо QueryStringValueProvider.
- Некоторое отражение, чтобы отобразить извлеченные числа в
Type
-s.
1. ValueProvider
Подробную статью о создании ValueProviders можно найти здесь:
В качестве отправной точки приведем некоторый код, который успешно извлекает целые числа WhatType из тела json:
public class BlahValueProvider : IValueProvider
{
private readonly string _requestBody;
public BlahValueProvider(string requestBody)
{
_requestBody = requestBody;
}
private const string PROPERTY_NAME = "WhatType";
public bool ContainsPrefix(string prefix)
{
return prefix == PROPERTY_NAME;
}
public ValueProviderResult GetValue(string key)
{
if (key != PROPERTY_NAME)
return ValueProviderResult.None;
// parse json
try
{
var json = JObject.Parse(_requestBody);
return new ValueProviderResult(json.Value<int>("WhatType").ToString());
}
catch (Exception e)
{
// TODO: error handling
throw;
}
}
}
public class BlahValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var request = context.ActionContext.HttpContext.Request;
if (request.ContentType == "application/json")
{
return AddValueProviderAsync(context);
}
return Task.CompletedTask;
}
private Task AddValueProviderAsync(ValueProviderFactoryContext context)
{
using (StreamReader sr = new StreamReader(context.ActionContext.HttpContext.Request.Body))
{
string bodyString = sr.ReadToEnd();
context.ValueProviders.Add(new BlahValueProvider(bodyString));
}
return Task.CompletedTask;
}
}
Конечно, вы должны зарегистрировать эту фабрику в Startup.cs так же, как вы зарегистрировали подшивку модели. И это абсолютно не позволяет преобразовать извлеченное число в фактический тип (для этого см. Пункт 2 ниже), но если вы разместите точку останова на своей строке, начиная с if (modelTypeValue != null
, вы увидите, что modelTypeValue теперь для вас, даже без отдельного GET параметр.
2. Отражение
Поймите, что вы пытаетесь определить тип на основе свойства, которое динамически вычисляется на существующем экземпляре (они не являются статическими). Хотя, зная текущую реализацию, я знаю, что это возможно (создать пустой экземпляр модели, проверить свойство WhatType
, выбросить экземпляр), но это очень плохая практика, поскольку ничто не гарантирует, что свойство экземпляра является статически постоянным .
Чистым решением для этого будет атрибут , который содержит номер WhatType для этого класса. Затем мы можем подумать об этом атрибуте и построить карту, которая отображает int
с Type
с. Это выходит за рамки этого вопроса, но посмотрите учебник по любым пользовательским атрибутам, если вы не знакомы, и вы сможете собрать его очень быстро.