为什么添加对象成功后状态码不成功
Why is the status code not successful after an object has been added successfully
我正在编写一个 C# 表单应用程序以 post 一些数据到 Web 服务。正在 posted 的对象已正确添加到数据库中,但客户端未收到 true
的 SuccessStatusCode
。
这是网络服务函数:
[Route("Postitem")]
[ResponseType(typeof(Item))]
public async Task<IHttpActionResult> PostItem(Item item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.items.Add(item);
await db.SaveChangesAsync();
var data = CreatedAtRoute("DefaultApi", new { id = item.Id }, item);
return data;
}
这里是客户端PostItem
函数:
public async Task PostItem()
{
var item = new Item(1, 0, "Posted Item Name 6", "Posted Item Data");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync("api/Postitem", item);
if (response.IsSuccessStatusCode)
{
}
}
}
response.IsSuccessStatusCode
的值为 false
。
这是响应的字符串值:
"StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1,
Content: System.Net.Http.StreamContent, Headers:\r\n{\r\n Pragma:
no-cache\r\n Cache-Control: no-cache\r\n Date: Tue, 26 Jan 2016
03:37:09 GMT\r\n Server: Microsoft-IIS/10.0\r\n X-AspNet-Version:
4.0.30319\r\n X-Powered-By: ASP.NET\r\n Content-Length: 1174\r\n Content-Type: application/json; charset=utf-8\r\n Expires: -1\r\n}"
客户端如何正确确定对象是否 posted 正确?
使用消除过程...如果一个语句成功,但该方法之后没有return,那会是什么?我猜你的 CreatedAtRoute 抛出了 500,因为你的项目被添加到你的数据库中,但该方法没有成功执行。
也许按照this回答的建议去做并尝试:
var data = CreatedAtRoute("DefaultApi", new { controller = "controllername", id = item.Id }, item);
return data;
显然,将 "controllername"
替换为您的控制器名称。 但是 路由属性与整个"DefaultApi"
的交互效果不是很好,因为我相信它们是在不同的路由名称下添加的。您可能真的想尝试 this 之类的东西,然后将 Name
属性 添加到您的 RouteAttribute
。这将创建一个明确的 routeName
,您可以在 CreatedAtRoute
中将其用作第一个参数。
但是,有一个问题。根据您的命名约定(您将路由命名为"Postitem",您没有得到CreatedAtRoute
的意义。此功能旨在促进RESTful服务。您的服务不是restful。您应该改为将您的路由命名为 "item"
并使用相同的路由使用相应的 GetItem
方法。其中一个接受 HTTP POST(您的 PostItem),另一个接受 HTTP GET。 CreatedAtRoute
旨在帮助调用函数了解它应该调用的 URL 以便
如果你不想走 restful 路线,你可以完全放弃 CreatedAtRoute
,然后这样做:
[Route("Postitem")]
[ResponseType(typeof(Item))]
public async Task<IHttpActionResult> PostItem(Item item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.items.Add(item);
await db.SaveChangesAsync();
return this.Ok(new { id = item.Id });
}
一般调试说明
如果您实际查看控制器的响应,您可能可以自己解决这个问题。使用类似 this or this 的内容。您发布的消息说它有 1174 个字节长。你想打赌它包含一个 JSON-formatted 异常,它会告诉你到底出了什么问题?
一般API备注
我注意到您直接传递实体(您将 item
直接添加到数据库中)。这是非常糟糕的,尤其是对于导航属性(它们会导致序列化程序中的无限循环)。我建议为您的 API 和您的数据库设置一个单独的模型。使您的方法接受的东西能够将其自身转换为数据库项,反之亦然。
编辑:阅读 JSON
的示例
首先,在某处声明一个 class,如下所示:
[DataContract] //found in System.Runtime.Serializatino
public class ItemResult
{
[DataMember(Name = "id")] //Same place as DataContractAttribute
public int Id { get; set; }
}
此 class 表示来自您的服务的响应。接下来,在你的客户端class(你声明PostItem
的地方...不是action方法,客户端方法),声明如下:
private static readonly JsonSerializer serializer = new JsonSerializer();
这是来自非常流行的 JSON.Net 库。如果您还没有安装它,请通过 nuget 安装它。
接下来,这是您的 PostItem 需要的样子:
public async Task<ItemResult> PostItem()
{
var item = new Item(1, 0, "Posted Item Name 6", "Posted Item Data");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var response = await client.PostAsJsonAsync("api/Postitem", item))
using (var rs = await response.Content.ReadAsStreamAsync())
using (var sr = new StreamRead(rs))
using (var jr = new JsonTextReader(sr))
{
if (response.IsSuccessStatusCode)
{
return serializer.Deserialize<ItemResult>(jr);
}
else
{
//deserialize as something else...an error message perhaps?
}
}
}
}
这里是对发生的事情的解释:
- 通过调用 PostAsJsonAsync
通过 POST 发出请求
- 使用响应中的内容并获取将包含服务器发回的内容的流。这是
response.Content.ReadAsStreamAsync
.
- 将该流包装在流中 reader(System.IO 的一部分)
- 将该流包装在 json 文本 reader 中(Newtonsoft.JSON 的一部分(JSON.Net 的命名空间))
- 检查状态代码是否成功(如果您想在出现错误时自动抛出异常,请改为调用
response.EnsureSuccessStatusCode
。
- 使用之前声明的
serializer
对象将服务器return编辑的JSON对象反序列化为ItemResponse
class.
我正在编写一个 C# 表单应用程序以 post 一些数据到 Web 服务。正在 posted 的对象已正确添加到数据库中,但客户端未收到 true
的 SuccessStatusCode
。
这是网络服务函数:
[Route("Postitem")]
[ResponseType(typeof(Item))]
public async Task<IHttpActionResult> PostItem(Item item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.items.Add(item);
await db.SaveChangesAsync();
var data = CreatedAtRoute("DefaultApi", new { id = item.Id }, item);
return data;
}
这里是客户端PostItem
函数:
public async Task PostItem()
{
var item = new Item(1, 0, "Posted Item Name 6", "Posted Item Data");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync("api/Postitem", item);
if (response.IsSuccessStatusCode)
{
}
}
}
response.IsSuccessStatusCode
的值为 false
。
这是响应的字符串值:
"StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:\r\n{\r\n Pragma: no-cache\r\n Cache-Control: no-cache\r\n Date: Tue, 26 Jan 2016 03:37:09 GMT\r\n Server: Microsoft-IIS/10.0\r\n X-AspNet-Version: 4.0.30319\r\n X-Powered-By: ASP.NET\r\n Content-Length: 1174\r\n Content-Type: application/json; charset=utf-8\r\n Expires: -1\r\n}"
客户端如何正确确定对象是否 posted 正确?
使用消除过程...如果一个语句成功,但该方法之后没有return,那会是什么?我猜你的 CreatedAtRoute 抛出了 500,因为你的项目被添加到你的数据库中,但该方法没有成功执行。
也许按照this回答的建议去做并尝试:
var data = CreatedAtRoute("DefaultApi", new { controller = "controllername", id = item.Id }, item);
return data;
显然,将 "controllername"
替换为您的控制器名称。 但是 路由属性与整个"DefaultApi"
的交互效果不是很好,因为我相信它们是在不同的路由名称下添加的。您可能真的想尝试 this 之类的东西,然后将 Name
属性 添加到您的 RouteAttribute
。这将创建一个明确的 routeName
,您可以在 CreatedAtRoute
中将其用作第一个参数。
但是,有一个问题。根据您的命名约定(您将路由命名为"Postitem",您没有得到CreatedAtRoute
的意义。此功能旨在促进RESTful服务。您的服务不是restful。您应该改为将您的路由命名为 "item"
并使用相同的路由使用相应的 GetItem
方法。其中一个接受 HTTP POST(您的 PostItem),另一个接受 HTTP GET。 CreatedAtRoute
旨在帮助调用函数了解它应该调用的 URL 以便
如果你不想走 restful 路线,你可以完全放弃 CreatedAtRoute
,然后这样做:
[Route("Postitem")]
[ResponseType(typeof(Item))]
public async Task<IHttpActionResult> PostItem(Item item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.items.Add(item);
await db.SaveChangesAsync();
return this.Ok(new { id = item.Id });
}
一般调试说明
如果您实际查看控制器的响应,您可能可以自己解决这个问题。使用类似 this or this 的内容。您发布的消息说它有 1174 个字节长。你想打赌它包含一个 JSON-formatted 异常,它会告诉你到底出了什么问题?
一般API备注
我注意到您直接传递实体(您将 item
直接添加到数据库中)。这是非常糟糕的,尤其是对于导航属性(它们会导致序列化程序中的无限循环)。我建议为您的 API 和您的数据库设置一个单独的模型。使您的方法接受的东西能够将其自身转换为数据库项,反之亦然。
编辑:阅读 JSON
的示例首先,在某处声明一个 class,如下所示:
[DataContract] //found in System.Runtime.Serializatino
public class ItemResult
{
[DataMember(Name = "id")] //Same place as DataContractAttribute
public int Id { get; set; }
}
此 class 表示来自您的服务的响应。接下来,在你的客户端class(你声明PostItem
的地方...不是action方法,客户端方法),声明如下:
private static readonly JsonSerializer serializer = new JsonSerializer();
这是来自非常流行的 JSON.Net 库。如果您还没有安装它,请通过 nuget 安装它。
接下来,这是您的 PostItem 需要的样子:
public async Task<ItemResult> PostItem()
{
var item = new Item(1, 0, "Posted Item Name 6", "Posted Item Data");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var response = await client.PostAsJsonAsync("api/Postitem", item))
using (var rs = await response.Content.ReadAsStreamAsync())
using (var sr = new StreamRead(rs))
using (var jr = new JsonTextReader(sr))
{
if (response.IsSuccessStatusCode)
{
return serializer.Deserialize<ItemResult>(jr);
}
else
{
//deserialize as something else...an error message perhaps?
}
}
}
}
这里是对发生的事情的解释:
- 通过调用 PostAsJsonAsync 通过 POST 发出请求
- 使用响应中的内容并获取将包含服务器发回的内容的流。这是
response.Content.ReadAsStreamAsync
. - 将该流包装在流中 reader(System.IO 的一部分)
- 将该流包装在 json 文本 reader 中(Newtonsoft.JSON 的一部分(JSON.Net 的命名空间))
- 检查状态代码是否成功(如果您想在出现错误时自动抛出异常,请改为调用
response.EnsureSuccessStatusCode
。 - 使用之前声明的
serializer
对象将服务器return编辑的JSON对象反序列化为ItemResponse
class.