我正在使用最新的 OData NuGet 包编写 OData V4 服务/Web API 2。我有一个问题,我认为是服务器上的格式问题或配置问题,但我是 OData 和 WebAPI 的新手,所以我可能错了。
问题是这样的:如果我用补丁调用我的 OData 服务,其中像“Mølgaard”这样的非美国字符串包含在指向已声明属性的字段和动态属性中,我会在我的补丁方法中获取控制器“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(existing) 之后,现有实例在其“SomeText”属性中包含正确编码的值,但在相应的 Dynamic 属性中不包含。