在这个简单的例子中,我试图从Web Api 2 + OData v4服务获取一个序列化为JSON的对象。控制器具有绑定功能Test,它返回一个annon数组。对象。
public class ProductsController : ODataController
{
[HttpGet]
public IHttpActionResult Test(int key)
{
var res = new[]
{
new { Name = "a", Value = new[] { 1, 2, 3 } },
new { Name = "b", Value = new[] { 2, 4, 5 } }
// this also produces same result
// new { Name = "a", Value = "c" },
// new { Name = "b", Value = "c" }
};
return this.Ok(res);
}
}
Edm是用这段代码构建的:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
var productType = builder.EntityType<Product>();
var f = productType.Function("Test").Returns<object>();
当我向服务发出请求时(例如http://localhost:9010/odata/Products(33)/Default.Test)我得到一个奇怪的响应 - 一个包含两个空对象的数组,如下所示:
{
"@odata.context": "http://localhost:9010/odata/$metadata#Collection(System.Object)",
"value": [
{},
{}
]
}
在我的真实应用程序中,我使用Newtonsoft的Json转换器将对象序列化为JSON字符串 - 这很好,但是这个问题仍然困扰着我。我怀疑它与OData的默认序列化程序有关,但我不清楚如何配置它。
那么,是否有可能以这种方式配置edm函数的返回参数,以便我能正确地序列化复杂对象?
谢谢!
答案 0 :(得分:5)
正如lukkea所说,OData不适用于匿名类型 旁注,在WebApiConfig中,如果要返回集合,则应将“返回”更改为“ReturnsCollection”。
无论如何,我们假设你写了以下内容。
return this.Ok(Newtonsoft.Json.JsonConvert.SerializeObject(res));
var f = productType.Function("Test").Returns<string>();
你会得到以下信息:
{
"@odata.context": "http://localhost/Test/odata/$metadata#Edm.String",
"value":
"[
{\"Name\":\"a\",\"Value\":[1,2,3]},
{\"Name\":\"b\",\"Value\":[2,4,5]}
]"
}
请注意,数组中仍有2个项目,但这次它们不是空的 由于OData在前一个示例中不知道返回类型,因此它返回没有值的2个对象。
您有2个选项。
选项1
// ON SERVER
return this.Ok(Newtonsoft.Json.JsonConvert.SerializeObject(res));
var f = productType.Function("Test").Returns<string>();
// ON CLIENT
string jsonString = odataContext.Products.ByKey(33).Test().GetValue();
var objectList = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonString);
string firstObjectName = objectList[0].Name;
选项2
// ON SERVER
public class TestObject
{
public string Name { get; set; }
public List<int> Integers { get; set; }
}
var res = new List<TestObject>
{
new TestObject { Name = "a", Integers = new List<int> { 1, 2, 3 } },
new TestObject { Name = "b", Integers = new List<int> { 2, 4, 5 } }
};
return this.Ok(res);
var f = productType.Function("Test").ReturnsCollection<TestObject>();
如果您想要返回一个具有非强类型的额外属性的人,那么您需要ODataOpenType
答案 1 :(得分:0)
使用动态响应确实很棘手,但这并不难,而且您当然不必求助于通过字符串编码返回对象。
关键是 dynamic 响应意味着我们不能使用标准的EnableQueryAttribute
在方法响应上应用特定的投影或过滤,并且我们不能返回{{ 1}},因为该响应对象旨在使运行时能够操纵如何将响应对象序列化为HTTP响应。
ApiController.Ok(T内容);
创建具有指定值的System.Web.Http.Results.OkNegotiatedContentResult。
内容 :要在实体主体中协商和格式化的内容值。
Content Negotiation
内容协商本质上是一种机制,用于封装确定如何您的方法响应如何通过http传输以及繁重的工作以物理方式编码响应的过程。通过使用内容协商,即使在请求中指定输出为XML(而不是标准JSON)的调用方,您的方法也只需要返回查询或原始c#对象。处理物理序列化的概念和解释调用者意图的逻辑被抽象出来,因此您完全不必担心它。
您可以使用2个选项来自定义输出:
ApiController.JsonResult(T content);
这样,您可以指定要序列化的对象图,而不会响应OkNegotiatedContentResult
或内容协商。
EnableQueryAttribute
return this.JsonResult(res);
属性,例如@odata
。@odata.context
或其他类型的接口。< / li>
HttpResponseMessage
一起绕过OData响应管理,并直接从您的方法中返回object
。这样,您负责序列化响应内容以及响应头。
但是,这绕过了所有OData机制,包括响应验证和格式化,这意味着您可以返回任何所需内容。
HttpResponseMessage