Привязка пользовательской модели WebAPI сложного абстрактного объекта

86
10

Это непросто. У меня проблема с привязкой модели от 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"
}
]
}

спросил(а) 2016-05-17T19:43:00+03:00 4 года, 9 месяцев назад
1
Решение
147

После некоторых исследований я обнаружил, что поставщики метаданных не существуют в 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)
{
}

ответил(а) 2016-05-20T18:56:00+03:00 4 года, 9 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема