为什么添加对象成功后状态码不成功

Why is the status code not successful after an object has been added successfully

我正在编写一个 C# 表单应用程序以 post 一些数据到 Web 服务。正在 posted 的对象已正确添加到数据库中,但客户端未收到 trueSuccessStatusCode

这是网络服务函数:

[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?
            }
        }

    }
}

这里是对发生的事情的解释:

  1. 通过调用 PostAsJsonAsync
  2. 通过 POST 发出请求
  3. 使用响应中的内容并获取将包含服务器发回的内容的流。这是 response.Content.ReadAsStreamAsync.
  4. 将该流包装在流中 reader(System.IO 的一部分)
  5. 将该流包装在 json 文本 reader 中(Newtonsoft.JSON 的一部分(JSON.Net 的命名空间))
  6. 检查状态代码是否成功(如果您想在出现错误时自动抛出异常,请改为调用 response.EnsureSuccessStatusCode
  7. 使用之前声明的serializer对象将服务器return编辑的JSON对象反序列化为ItemResponseclass.