Привязка пользовательской модели WebAPI сложного абстрактного объекта
Это непросто. У меня проблема с привязкой модели от JSON. Я пытаюсь разрешить polyorphic-ally запись, предоставленную с типом записи, которую он разрешит (я хочу иметь возможность добавлять много типов записей в будущем). Я попытался использовать следующий пример, чтобы разрешить мою модель при вызове конечной точки, но этот пример работает только для приложений MVC, а не для веб-API.
Я попытался написать его с помощью IModelBinder и BindModel (HttpActionContext actionContext, ModelBindingContext bindingContext). Однако я не могу найти эквивалент ModelMetadataProviders в пространстве имен System.Web.Http.
Оцените любую помощь, которую любой может дать.
У меня есть приложение Web API 2, которое имеет следующую структуру объектов.
public abstract class ResourceRecord
{
public abstract string Type { get; }
}
public class ARecord : ResourceRecord
{
public override string Type
{
get { return "A"; }
}
public string AVal { get; set; }
}
public class BRecord : ResourceRecord
{
public override string Type
{
get { return "B"; }
}
public string BVal { get; set; }
}
public class RecordCollection
{
public string Id { get; set; }
public string Name { get; set; }
public List<ResourceRecord> Records { get; }
public RecordCollection()
{
Records = new List<ResourceRecord>();
}
}
Структура JSON
{
"Id": "1",
"Name": "myName",
"Records": [
{
"Type": "A",
"AValue": "AVal"
},
{
"Type": "B",
"BValue": "BVal"
}
]
}
После некоторых исследований я обнаружил, что поставщики метаданных не существуют в WebAPI и для привязки к сложным абстрактным объектам вы должны писать свои собственные.
Я начал с написания нового метода привязки модели с использованием пользовательского типа JSon serializer и, наконец, я обновил свою конечную точку, чтобы использовать настраиваемое связующее. Стоит отметить, что следующее будет работать только с запросами в теле, вам нужно будет написать что-то еще для запросов в заголовке. Я бы предложил прочитать главу 16 Адама Фримана Эксперт ASP.NET Web API 2 для разработчиков MVC и сложное связывание объектов.
Мне удалось выполнить сериализацию моего объекта из тела запроса, используя следующий код.
Конфигурация WebAPI
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Services.Insert(typeof(ModelBinderProvider), 0,
new SimpleModelBinderProvider(typeof(RecordCollection), new JsonBodyModelBinder<RecordCollection>()));
}
}
Пользовательское связующее устройство
public class JsonBodyModelBinder<T> : IModelBinder
{
public bool BindModel(HttpActionContext actionContext,
ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(T))
{
return false;
}
try
{
var json = ExtractRequestJson(actionContext);
bindingContext.Model = DeserializeObjectFromJson(json);
return true;
}
catch (JsonException exception)
{
bindingContext.ModelState.AddModelError("JsonDeserializationException", exception);
return false;
}
return false;
}
private static T DeserializeObjectFromJson(string json)
{
var binder = new TypeNameSerializationBinder("");
var obj = JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = binder
});
return obj;
}
private static string ExtractRequestJson(HttpActionContext actionContext)
{
var content = actionContext.Request.Content;
string json = content.ReadAsStringAsync().Result;
return json;
}
}
Пользовательская привязка Serialization
public class TypeNameSerializationBinder : SerializationBinder
{
public string TypeFormat { get; private set; }
public TypeNameSerializationBinder(string typeFormat)
{
TypeFormat = typeFormat;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
public override Type BindToType(string assemblyName, string typeName)
{
string resolvedTypeName = string.Format(TypeFormat, typeName);
return Type.GetType(resolvedTypeName, true);
}
}
Определение конечной точки
[HttpPost]
public void Post([ModelBinder(BinderType = typeof(JsonBodyModelBinder<RecordCollection>))]RecordCollection recordCollection)
{
}
Еще в рубрике
- Вопросы
- Model-binding
- Привязка пользовательской модели WebAPI сложного абстрактного объекта