gpt4 book ai didi

c# - 如何在 OData C# 驱动程序中支持嵌套的开放式复杂类型?

转载 作者:行者123 更新时间:2023-11-30 15:54:15 29 4
gpt4 key购买 nike

我在 .NET Web Api 项目中使用以下 C# OData 包:

Install-Package Microsoft.AspNet.OData
Install-Package Microsoft.AspNet.WebApi.OData

当遵循 Microsoft 的示例时 Use Open Types in OData v4 ,一切似乎都按预期工作,只要开放类型不包含其他嵌套的开放复杂类型。

这意味着它可以正常工作:

public class WplController : ODataController
{
private List<AbstractMongoDocument> _documents = new List<AbstractMongoDocument>
{
new AbstractMongoDocument
{
Id = "2",
Meta = new MongoMeta(),
Data = new MongoData
{
Document = new Dictionary<string, object>()
{
{"root_open_type", "This works!" },
}
}
}
};

[EnableQuery]
public IQueryable<AbstractMongoDocument> Get()
{ return _documents.AsQueryable();}
}

虽然这会抛出异常

public class WplController : ODataController
{
private List<AbstractMongoDocument> _documents = new List<AbstractMongoDocument>
{
new AbstractMongoDocument
{
Id = "1",
Meta = new MongoMeta(),
Data = new MongoData
{
Document = new Dictionary<string, object>()
{
{"root_open_type", "This works!" },
{"nested_open_type", new Dictionary<string, object>() //Nested dictionary throws exception!
{
{"field1", "value2" },
{"field2", "value2" }
}
}
}
}
}
};

[EnableQuery]
public IQueryable<AbstractMongoDocument> Get()
{ return _documents.AsQueryable();}
}

异常情况如下:

System.InvalidOperationException occurred

Message: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.

Message: Exception thrown: 'System.InvalidOperationException' in System.Web.OData.dll

Additional information: The given model does not contain the type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]'.


这可以通过将以下行添加到 WebApiConfig.cs 中的 ODataConventionModelBuilder 来解决:

builder.ComplexType<Dictionary<string, object>>();

但是,这会导致以下 OData 响应 JSON:

 {
"@odata.context": "http://localhost:50477/odata/$metadata#wpl",
"value":
[
{
"Id": "1",
"Meta": {},
"Data":
{
"root_open_type": "This works!",
"nested_open_type":
{
"@odata.type": "#System.Collections.Generic.Dictionary_2OfString_Object",
"Keys":
[
"field1",
"field2"
]
}
}
}
]
}

如何确保 ODate 也正确序列化嵌套的开放字段? IE。我想要以下生成的 OData JSON:

 {
"@odata.context": "http://localhost:50477/odata/$metadata#wpl",
"value":
[
{
"Id": "1",
"Meta": {},
"Data":
{
"root_open_type": "This works!",
"nested_open_type":
{
"field1": "value1",
"field2": "value2"
}
}
}
]
}

提前感谢您提供的任何帮助!

最佳答案

我和你在同一条船上。我需要将一些数据公开为纯 JSON。这是一个使用 ODataUntypedValue 类的有效解决方案。它序列化为您所期望的。我用你和我的模型测试了它。

实现一个 MongoDataSerializer 类:

public class MongoDataSerializer: ODataResourceSerializer
{
public MongoDataSerializer(ODataSerializerProvider serializerProvider)
: base(serializerProvider)
{
}

/// <summary>
/// Serializes the open complex type as an <see cref="ODataUntypedValue"/>.
/// </summary>
/// <param name="graph"></param>
/// <param name="expectedType"></param>
/// <param name="writer"></param>
/// <param name="writeContext"></param>
public override void WriteObjectInline(
object graph,
IEdmTypeReference expectedType,
ODataWriter writer,
ODataSerializerContext writeContext)
{
// This cast is safe because the type is checked before using this serializer.
var mongoData = (MongoData)graph;
var properties = new List<ODataProperty>();

foreach (var item in mongoData.Document)
{
properties.Add(new ODataProperty
{
Name = item.Key,
Value = new ODataUntypedValue
{
RawValue = JsonConvert.SerializeObject(item.Value),
},
});
}

writer.WriteStart(new ODataResource
{
TypeName = expectedType.FullName(),
Properties = properties,
});

writer.WriteEnd();
}
}

实现一个 CustomODataSerializerProvider 类:

public class CustomODataSerializerProvider : DefaultODataSerializerProvider
{
private readonly MongoDataSerializer mongoDataSerializer;

public CustomODataSerializerProvider(
IServiceProvider odataServiceProvider)
: base(odataServiceProvider)
{
this.mongoDataSerializer = new MongoDataSerializer(this);
}

public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.FullName() == typeof(MongoData).FullName)
{
return this.mongoDataSerializer;
}

return base.GetEdmTypeSerializer(edmType);
}
}

Startup.cs 中注册 CustomODataSerializerProvider:

        app.UseMvc(options =>
{
var model = builder.GetEdmModel();
options
.MapODataServiceRoute(
"odata",
"odata",
b => b
.AddService(Microsoft.OData.ServiceLifetime.Scoped, s => model)
.AddService<IEnumerable<IODataRoutingConvention>>(
Microsoft.OData.ServiceLifetime.Scoped,
s => ODataRoutingConventions.CreateDefaultWithAttributeRouting("odata", options))
.AddService<ODataSerializerProvider, CustomODataSerializerProvider>(Microsoft.OData.ServiceLifetime.Singleton));
}

这是使用您的模型的输出(请注意属性名称以小写字母开头,因为我启用了 ODataConventionModelBuilder.EnableLowerCamelCase()): Working output

关于c# - 如何在 OData C# 驱动程序中支持嵌套的开放式复杂类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50682776/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com