Web Api 2 使用集合 属性 反序列化 LINQ2SQL 对象
Web Api 2 deserialize LINQ2SQL object with collection property
上下文很长,所以我将从问题开始:为什么 InductionQAs 集合 属性 没有被再水化?
在 Web API 2 方法中,LINQ 生成一个对象 ic
和一个集合 属性 InductionQAs
。在我消除了一个巨大的无关对象图并防止循环引用之后,该方法返回了ic
。这是代码。为简洁起见,删除了错误处理。
// GET: api/InductionContent/5
[Authorize]
public object Get(int id)
{
var dc = new Models.InductionsDataContext();
var user = GetUser(dc);
var ic = dc.InductionContents.Single(c => c.InductionContentID == id);
ic.User.InductionContents.Clear(); //don't ship this it can be huge
return ic;
}
调用JS代码如下。忽略授权头业务,一切正常。
var token, headers;
$.ajax({ //get session token
url: "api/token",
headers: { Authorization: "Basic " + btoa("username:password") },
}).done(function (result) {
localStorage.setItem('access_token', token = result.access_token);
var headers = { Authorization: "Session " + token };
$.ajax({ //get an induction content object
url: "api/InductionContent/5",
headers: headers
}).done(function (ic) {
//at this point we have an object graph
var json = JSON.stringify(ic);
});
});
这就是 JSON.stringify(ic) returns:
{
"InductionContentID": 5,
"InductionTemplateID": 1,
"InductionContent1": "<p>We recognise that it is ...(redacted)</p>",
"InductionContentOrder": 301,
"Caption": "Workplace Health and Safety",
"OwnerId": 0,
"ParentId": 0,
"TopicId": 5,
"InductionQAs": [
{
"InductionQAID": 1,
"InductionContentID": 5,
"Question": "Who is responsible for ...(redacted)",
"Answers": "A|B|C|*D",
"InductionQAOrder": 1
}
],
"User": null
}
一切都很好。现在我们往返。
$.ajax({
type: "post",
url: "api/InductionContent",
headers: headers,
data: ic
});
这会调用以下网络方法:
// POST: api/InductionContent
[Authorize]
public void Post([FromBody]Models.InductionContent ic)
{
//redacted
}
方法被调用并且ic
有一个值。 ic.User
包含数据,但检查 ic.InductionQAs
显示它尚未初始化。
序列化配置如下:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.MessageHandlers
.Add(new AuthenticationHandler(CreateConfiguration()));
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
MVC 很聪明,但还不够聪明。它需要一个提示。 "round-trip" 调用 应该 看起来像这样:
$.ajax({
type: "post",
url: "api/InductionContent",
contentType: "text/json",
headers: headers,
data: JSON.stringify(ic)
}).done(function (result) {
//etc
});
这里有两点需要注意。
- 我们假设有效载荷编码是手动控制的
- 我们已经用使用的编码注释了 post
另一件事...
一切正常后,我决定该方法应该 return 新创建的数据库行的 ID。将方法 return 类型更改为 int
并附加最后一行
return nc.InductionContentId;
应该已经足够了,但是 ajax 调用的 done 方法完全无法触发。使用 Fiddler 进行的调查显示,id 值确实 returned ,内容类型为 text/json。
当您为 jQuery ajax 调用指定内容类型时,相同的内容类型将用于响应。如果 return 值是一个对象,这将工作正常。该对象将被序列化为 JSON 并且在另一端将被解析以提供结果对象。
但是对于像 int 这样的简单值,这在解析阶段就没有了。要解决此问题,请使用 dataType 属性 return 纯文本内容类型。
$.ajax({
type: "post",
url: "api/InductionContent",
contentType: "text/json",
dataType: "text",
headers: headers,
data: JSON.stringify(ic)
}).done(function (result) {
var id = result;
//etc
});
上下文很长,所以我将从问题开始:为什么 InductionQAs 集合 属性 没有被再水化?
在 Web API 2 方法中,LINQ 生成一个对象 ic
和一个集合 属性 InductionQAs
。在我消除了一个巨大的无关对象图并防止循环引用之后,该方法返回了ic
。这是代码。为简洁起见,删除了错误处理。
// GET: api/InductionContent/5
[Authorize]
public object Get(int id)
{
var dc = new Models.InductionsDataContext();
var user = GetUser(dc);
var ic = dc.InductionContents.Single(c => c.InductionContentID == id);
ic.User.InductionContents.Clear(); //don't ship this it can be huge
return ic;
}
调用JS代码如下。忽略授权头业务,一切正常。
var token, headers;
$.ajax({ //get session token
url: "api/token",
headers: { Authorization: "Basic " + btoa("username:password") },
}).done(function (result) {
localStorage.setItem('access_token', token = result.access_token);
var headers = { Authorization: "Session " + token };
$.ajax({ //get an induction content object
url: "api/InductionContent/5",
headers: headers
}).done(function (ic) {
//at this point we have an object graph
var json = JSON.stringify(ic);
});
});
这就是 JSON.stringify(ic) returns:
{
"InductionContentID": 5,
"InductionTemplateID": 1,
"InductionContent1": "<p>We recognise that it is ...(redacted)</p>",
"InductionContentOrder": 301,
"Caption": "Workplace Health and Safety",
"OwnerId": 0,
"ParentId": 0,
"TopicId": 5,
"InductionQAs": [
{
"InductionQAID": 1,
"InductionContentID": 5,
"Question": "Who is responsible for ...(redacted)",
"Answers": "A|B|C|*D",
"InductionQAOrder": 1
}
],
"User": null
}
一切都很好。现在我们往返。
$.ajax({
type: "post",
url: "api/InductionContent",
headers: headers,
data: ic
});
这会调用以下网络方法:
// POST: api/InductionContent
[Authorize]
public void Post([FromBody]Models.InductionContent ic)
{
//redacted
}
方法被调用并且ic
有一个值。 ic.User
包含数据,但检查 ic.InductionQAs
显示它尚未初始化。
序列化配置如下:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.MessageHandlers
.Add(new AuthenticationHandler(CreateConfiguration()));
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
MVC 很聪明,但还不够聪明。它需要一个提示。 "round-trip" 调用 应该 看起来像这样:
$.ajax({
type: "post",
url: "api/InductionContent",
contentType: "text/json",
headers: headers,
data: JSON.stringify(ic)
}).done(function (result) {
//etc
});
这里有两点需要注意。
- 我们假设有效载荷编码是手动控制的
- 我们已经用使用的编码注释了 post
另一件事...
一切正常后,我决定该方法应该 return 新创建的数据库行的 ID。将方法 return 类型更改为 int
并附加最后一行
return nc.InductionContentId;
应该已经足够了,但是 ajax 调用的 done 方法完全无法触发。使用 Fiddler 进行的调查显示,id 值确实 returned ,内容类型为 text/json。
当您为 jQuery ajax 调用指定内容类型时,相同的内容类型将用于响应。如果 return 值是一个对象,这将工作正常。该对象将被序列化为 JSON 并且在另一端将被解析以提供结果对象。
但是对于像 int 这样的简单值,这在解析阶段就没有了。要解决此问题,请使用 dataType 属性 return 纯文本内容类型。
$.ajax({
type: "post",
url: "api/InductionContent",
contentType: "text/json",
dataType: "text",
headers: headers,
data: JSON.stringify(ic)
}).done(function (result) {
var id = result;
//etc
});