如何使用C#中的HttpClient读取WebAPI响应

19

我开发了一个小的WebAPI,它有几个请求并返回我的自定义类Response

Response

public class Response
{
    bool IsSuccess=false;
    string Message;
    object ResponseData;

    public Response(bool status, string message, object data)
    {
        IsSuccess = status;
        Message = message;
        ResponseData = data;
    }
}

我的Web API及其操作

[RoutePrefix("api/customer")]
public class CustomerController : ApiController
{
    static readonly ICustomerRepository repository = new CustomerRepository();

    [HttpGet, Route("GetAll")]
    public Response GetAllCustomers()
    {
        return new Response(true, "SUCCESS", repository.GetAll());
    }

    [HttpGet, Route("GetByID/{customerID}")]
    public Response GetCustomer(string customerID)
    {
        Customer customer = repository.Get(customerID);
        if (customer == null)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        return new Response(true, "SUCCESS", customer);
        //return Request.CreateResponse(HttpStatusCode.OK, response);
    }

    [HttpGet, Route("GetByCountryName/{country}")]
    public IEnumerable<Customer> GetCustomersByCountry(string country)
    {
        return repository.GetAll().Where(
            c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
    }
}

目前我的困境是我不知道如何读取从WebAPI操作返回的响应数据,并从我的响应类中提取JSON。 在获取JSON后,我应该如何将其反序列化为客户类。

这是我调用WebAPI函数的方式:

private void btnLoad_Click(object sender, EventArgs e)
{
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:8010/");
    // Add an Accept header for JSON format.  
    //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    // List all Names.  
    HttpResponseMessage response = client.GetAsync("api/customer/GetAll").Result;  // Blocking call!  
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine("Request Message Information:- \n\n" + response.RequestMessage + "\n");
        Console.WriteLine("Response Message Header \n\n" + response.Content.Headers + "\n");
    }
    else
    {
        Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
    }
    Console.ReadLine();   
}
问题
  1. 如何在客户端获取WebAPI返回的响应类

  2. 如何从响应类中提取json

  3. 如何在客户端将json反序列化为客户类


我使用了这段代码,但仍然出现错误。

    var baseAddress = "http://localhost:8010/api/customer/GetAll";
    using (var client = new HttpClient())
    {
        using (var response =  client.GetAsync(baseAddress).Result)
        {
            if (response.IsSuccessStatusCode)
            {
                var customerJsonString = await response.Content.ReadAsStringAsync();
                var cust = JsonConvert.DeserializeObject<Response>(customerJsonString);
            }
            else
            {
                Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }
        }
    }

错误内容为:

发生了类型为 'Newtonsoft.Json.JsonSerializationException' 的异常,但未在用户代码中处理。

其他信息: 无法将当前的 JSON 对象(例如 {"name":"value"})反序列化为类型 'WebAPIClient.Response[]',因为该类型需要一个 JSON 数组(例如 [1,2,3])才能正确反序列化。

为什么响应会引起此错误?


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Murray Foxcroft
当我像这样阅读 var customerJsonString = await response.Content.ReadAsStringAsync(); 时,只会在customerJsonString变量中得到这个符号 {}。我犯了什么错误? - Monojit Sarkar
1
当您打开浏览器并导航到:http://localhost:8010/api/customer/GetAll时会发生什么情况?是否返回结果?(即在没有客户端代码的情况下测试API)。 - Murray Foxcroft
1
我不太确定你为什么创建了一个“Response”类。从你的API中,你应该能够直接从你的存储库返回对象(或在这种情况下,对象列表)。在客户端,你只需要通过response.Content.ReadAsStringAsync();获取响应字符串(即JSON),然后你可以使用类似JsonConvert的工具将该Json字符串反序列化为C#对象。你需要在客户端中使用相同的类来进行反序列化 - 可以创建一个共享库或其他东西,以便在两个项目中导入它(仅供参考)。 - Geoff James
2个回答

37
在客户端,包括对内容的读取:
    HttpResponseMessage response = client.GetAsync("api/customer/GetAll").Result;  // Blocking call!  
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine("Request Message Information:- \n\n" + response.RequestMessage + "\n");
        Console.WriteLine("Response Message Header \n\n" + response.Content.Headers + "\n");
        // Get the response
        var customerJsonString = await response.Content.ReadAsStringAsync();
        Console.WriteLine("Your response data is: " + customerJsonString);

        // Deserialise the data (include the Newtonsoft JSON Nuget package if you don't already have it)
        var deserialized = JsonConvert.DeserializeObject<IEnumerable<Customer>>(custome‌​rJsonString);
        // Do something with it
    }

将您的WebApi更改为不使用Response类,而是使用CustomerIEnumerable。使用HttpResponseMessage响应类。

您的WebAPI应仅需要:

[HttpGet, Route("GetAll")]
public IEnumerable<Customer> GetAllCustomers()
{
    var allCustomers = repository.GetAll();
    // Set a breakpoint on the line below to confirm
    // you are getting data back from your repository.
    return allCustomers;
}

根据评论中的讨论,我添加了一个基于通用响应类的代码,尽管我仍然建议您不要这样做,并避免将您的类命名为“Response”。您应该返回HTTP状态码而不是自己的状态码。例如200 OK、401未授权等。此外,此帖子介绍了如何返回HTTP状态码。

    public class Response<T>
    {
        public bool IsSuccess { get; set; }
        public string Message { get; set; }
        public IEnumerable<T> ResponseData { get; set; }

        public Response(bool status, string message, IEnumerable<T> data)
        {
            IsSuccess = status;
            Message = message;
            ResponseData = data;
        }
    }

1
刚想做,但这样可以省去我写同样答案的麻烦 :) 另外,你还可以使用Json.NET(Newtonsoft.Json)在客户端将你的Json字符串反序列化为C#类 - 例如:var deserialized = JsonConvert.DeserializeObject<IEnumerable<Customer>>(customerJsonString); - Geoff James
如果我返回一个包含许多内容的响应类,而不是IEnumerable<Customer>,那么会有什么问题吗? - Monojit Sarkar
1
我真的建议你避免将类名命名为“Response”,而是返回HTTP状态码,而不是自己定义的状态码。例如200 OK、401未经授权等(请参见https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)。另请参见https://dev59.com/BGgv5IYBdhLWcg3wXPot。我在你的Response类中看到的错误是ResponseData是一个对象,但应该是IEnumerable<object>,或者更高级一点,它应该是IEnumerable<T>(泛型)。 - Murray Foxcroft
1
@MonojitSarkar - 你为什么要返回自己的响应类?正如我在OP的评论中已经说过的,Murray也说得很对 - 这没有任何意义;你只是完全不必要地抽象化了你所返回的内容。在发送/消费API数据时的最佳实践是尽可能从存储库(数据库等)返回对象/对象列表,并通过HTTP状态代码处理未经授权/无效请求 - 这些代码是统一的,这就是它们的作用!你不需要重新发明轮子! - Geoff James
1
对于WebApi,你应该返回一个400 Bad Request。请按照这篇文章操作:http://www.asp.net/web-api/overview/error-handling/exception-handling - Murray Foxcroft
显示剩余7条评论

6

或者你可以在同一个呼叫中进行转换

  TResponse responseobject = response.Content.ReadAsAsync<TResponse>().Result;
            responseJson += "hostResponse: " + JsonParser.ConvertToJson(responseobject);
            //_logger.Debug($"responseJson : {responseJson}", correlationId);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接