【问题标题】:Why is the status code not successful after an object has been added successfully为什么添加对象成功后状态码不成功
【发布时间】:2016-05-02 14:19:42
【问题描述】:

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

这里是webservice函数:

[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: '内部服务器错误', 版本: 1.1, 内容:System.Net.Http.StreamContent,标头:\r\n{\r\n Pragma: 无缓存\r\n 缓存控制:无缓存\r\n 日期:2016 年 1 月 26 日,星期二 格林威治标准时间 03:37:09\r\n 服务器:Microsoft-IIS/10.0\r\n X-AspNet-版本: 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 过期:-1\r\n}"

客户端如何正确判断对象是否正确发布?

【问题讨论】:

  • 不太确定你在找什么——你的服务不应该在成功的情况下抛出异常......有很多关于如何调试 ASP.Net 站点的资源——很明显你不是在寻找教程...
  • 没有抛出异常,数据添加成功,但是客户端没有收到成功状态码。
  • 我认为返回OK(数据)
  • StatusCode: 500 仍然返回 OK(data)。

标签: c# asp.net-web-api2 httpresponse


【解决方案1】:

使用排除过程...如果一个语句成功,但之后该方法没有返回,那会是什么?我猜您的 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 服务。您的服务并不安静。您应该将路线命名为@987654334 @ 并有一个对应的 GetItem 方法具有相同的路由。其中一个接受 HTTP POST(您的 PostItem),一个接受 HTTP GET。CreatedAtRoute 旨在帮助调用函数知道它应该按顺序调用的 URL到

如果你不想走宁静的路线,你可以完全放弃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 });
}

一般调试说明

如果您实际查看控制器的响应,您可能可以自己解决此问题。使用thisthis 之类的内容。您发布的消息说它有 1174 字节长。你想打赌它包含一个 JSON 格式的异常,可以准确地告诉你出了什么问题?

通用 API 说明

我注意到您正在直接传递实体(您将 item 直接添加到您的数据库中)。这非常糟糕,尤其是导航属性(它们会导致序列化程序中的无限循环)。我建议为您的 API 和数据库使用单独的模型。使您的方法接受的东西能够将自己转换为数据库项目,反之亦然。

编辑:读取 JSON 的示例

首先,在某处声明一个如下所示的类:

[DataContract] //found in System.Runtime.Serializatino
public class ItemResult
{
    [DataMember(Name = "id")] //Same place as DataContractAttribute
    public int Id { get; set; }
}

此类表示来自您的服务的响应。接下来,在您的客户端类中(您声明PostItem...而不是操作方法,客户端方法的地方),声明以下内容:

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

【讨论】:

  • 谢谢,我已经放弃了 CreatedAtRoute,但是如何在客户端获取正在返回的 id 值的最佳方式?
  • this.Ok(new { id = item.Id }) 将传回一个 JSON 文档。您需要在帖子完成后打开响应流并阅读它。你想要一个例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 2015-01-13
  • 2020-01-14
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
相关资源
最近更新 更多