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

时间:2016-01-26 03:43:21

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

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

这是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,Headers:\ r \ n {\ r \ n Pragma:   no-cache \ r \ n缓存控制:无缓存\ r \ n日期:星期二,2016年1月26日   03:37:09 GMT \ 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}“

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

1 个答案:

答案 0 :(得分:2)

使用消除过程...如果一个语句成功,但该方法在此之后没有返回,那么它可能是什么?我猜你的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服务。您的服务并不宁静。您应该改名您的路由"item"并且具有相同路由的相应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
  2. 通过POST发出请求
  3. 使用响应中的内容并获取包含服务器发回的内容的流。这是response.Content.ReadAsStreamAsync
  4. 在流阅读器(System.IO的一部分)
  5. 中包裹该流
  6. 在json文本阅读器中包装该流(Newtonsoft.JSON(JSON.Net的命名空间)的一部分)
  7. 检查状态代码是否成功(如果您想在出现错误时自动抛出异常,请改为调用response.EnsureSuccessStatusCode
  8. 使用先前声明的serializer对象将服务器返回的JSON对象反序列化为ItemResponse类。