Я пишу сервис OData V4 / Web API 2 с последними пакетами OData NuGet.У меня проблема, я думаю, это проблема форматирования или, возможно, проблема конфигурации на сервере, но я новичок в OData и WebAPI, поэтому я, вероятно, ошибаюсь.
Проблема заключается в следующем: если я вызываю ODataСлужба с патчем, в которой неиспользуемая строка, такая как «Mølgaard», содержится как в поле, которое указывает на объявленное свойство, так и в динамическое свойство, я получаю в своем методе patch мой контроллер «Mølgaard» в объявленном свойстве, но вИз динамических свойств я получаю необработанное значение "M \ u00f8lgaard".Ожидаемое поведение заключается в том, чтобы получить «Mølgaard» в обоих случаях, и я нахожу очень странным то, что динамические свойства обрабатываются иначе, чем объявленные POCO-свойства.Я попробовал это с сгенерированным MS ODataClient, привязанным к моему сервису, а также с помощью инструмента Postman, в обоих случаях я использую метод Patch с тем же неправильным значением.
Будучи очень новым для OData, я имеюпопытался добавить новый сериализатор, как описано здесь: http://odata.github.io/WebApi/#06-03-costomize-odata-formatter и оттуда изменения, как описано в ответе здесь: OData WebApi V4 .net - Пользовательская сериализация Я также нашел пример использования Newtonsoft.Json.JsonConvert.Короче говоря, ни один из них не помог, и я предполагаю, что ни один из них на самом деле не предназначен для решения этой проблемы.
Я начал с демонстрационного проекта, который нашел здесь: https://github.com/DevExpress-Examples/XPO_how-to-implement-odata4-service-with-xpo
У меня естьдобавил класс POCO следующим образом:
public class OOrder : IDynamicProperties
{
[System.ComponentModel.DataAnnotations.Key]
public int ID { get; set; }
// SomeText is the declared property and its value
// is then repeated in DynamicProperties with another name
public string SomeText { get; set; }
public IDictionary<string, object> DynamicProperties { get; set; }
}
// I do not know if I need this, I am using
// it in a map function
public interface IDynamicProperties
{
IDictionary<string, object> DynamicProperties { get; set; }
}
И мой конфиг довольно прост:
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
ODataModelBuilder modelBuilder = CreateODataModelBuilder();
ODataBatchHandler batchHandler = new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer);
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: modelBuilder.GetEdmModel(),
batchHandler: batchHandler);
}
static ODataModelBuilder CreateODataModelBuilder()
{
ODataModelBuilder builder = new ODataModelBuilder();
var openOrder = builder.EntityType<OOrder>();
openOrder.HasKey(p => p.ID);
openOrder.Property(p => p.SomeText);
openOrder.HasDynamicProperties(p => p.DynamicProperties);
builder.EntitySet<OOrder>("OOrders");
return builder;
}
}
И моя функция исправления на моем контроллере выглядит следующим образом:
[HttpPatch]
public IHttpActionResult Patch([FromODataUri] int key, Delta<OOrder> order)
{
if (!ModelState.IsValid) return BadRequest();
using (UnitOfWork uow = ConnectionHelper.CreateSession()) {
OOrder existing = getSingle(key, uow);
if (existing != null) {
Order existingOrder = uow.GetObjectByKey<Order>(key);
order.CopyChangedValues(existing);
mapOpenWithDynamcPropertiesToPersisted(existing, existingOrder);
// Intentionally not storing changes for now
//uow.CommitChanges();
return Updated(existing);
}
else {
return NotFound();
}
}
}
private void mapOpenWithDynamcPropertiesToPersisted<TOpen, TPersisted>(TOpen open, TPersisted persisted)
where TPersisted : BaseDocument
where TOpen: IDynamicProperties {
if (open != null && persisted != null && open.DynamicProperties != null && open.DynamicProperties.Any()) {
XPClassInfo ci = persisted.ClassInfo;
foreach (string propertyName in open.DynamicProperties.Keys) {
var member = ci.FindMember(propertyName);
if (member != null) {
object val = open.DynamicProperties[propertyName];
// Here, I have tried to deserialize etc
member.SetValue(persisted, val);
}
}
}
}
После вызова метода order.CopyChangedValues (существующий) существующий экземпляр содержит правильно закодированное значение в свойстве SomeText, но не в соответствующем свойстве Dynamic.