RestSharp 如何处理同一查询的不同 JSON 响应格式

RestSharp How to deal with different JSON response formats for same query

我已经为此苦恼了一段时间,我想是时候寻求帮助了。

我正在使用 RestSharp 连接到我的本地 PHP REST API。我返回 api 结果的格式如下 (JSON):

{
"estado": "login_correcto",
"content": {
   "id": 1,
   "nombreusuario": "daniaguado",
   "contrasena": "qwerty",
   "email": "daniel@zadecon.com",
   "nivelacceso": 5,
    "created_at": "2017-08-01 10:31:16",
    "updated_at": "-0001-11-30 00:00:00"
    }
}

为此,我创建了一个自定义 Usuario class(用户)和一个自定义 ResponseUsuario,如下所示:

class Usuario
{
    public int id { get; set; }
    public string nombreusuario { get; set; }
    public string contrasena { get; set; }
    public string email { get; set; }
    public int nivelacceso { get; set; }
    public string created_at { get; set; }
    public string updated_at { get; set; }
}

然后 ResponseUsuario:

class ResponseUsuario
{
    public string estado { get; set; }
    public Usuario content { get; set; }
}

当响应正确 (202) 并且用户存在时,响应正在被正确解析。

但是,当登录不正确时,在 "content" 我返回的是一条消息,而不是用户:

{
 "estado": "login_incorrecto",
 "content": "La contraseña es incorrecta / Password incorrect"
}

所以,如果我在那里使用 ResponseUsuario,queryResult.Data 为空,因为它无法将内容映射到 Usuario class。事实是,如果我不使用 ResponseUsuario 而是使用 Response class,其中内容变量是类型对象,我无法将其转换为 Usuario 并且我无法处理它.

这是更通用的 Response class,据我所知,我应该将其用于我的所有查询:

class Response
{
    public string estado { get; set; }
    public object content { get; set; }
}

最后,这是我的 RestSharp 查询:

ApiClient api = new ApiClient(); // Just create the client with some common parameters

var request = new RestRequest("usuarios/login", RestSharp.Method.POST);

request.AddParameter("nombreusuario", textbox_usuario.Text);
request.AddParameter("contrasena", textbox_contrasena.Text);

var queryResult = api.cliente.Execute<ResponseUsuario>(request);

if (queryResult.StatusCode == System.Net.HttpStatusCode.OK)
{
    Usuario u = (Usuario) queryResult.Data.content; // Gives error when using Execute<Response> (object content)
    String s = queryResult.Data.estado;

    Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
} 
else
{
    Console.Out.WriteLineAsync($"Query Failed: {queryResult.StatusDescription}, estado: {queryResult.Data.estado}"); // Giving error when using Execute<ResponseUsuario>
}

如何将演员表固定为 Usuario(或内容的匹配 class)?我认为 Response class 应该对我对 API 的所有查询都是通用的,然后将内容部分转换为合适的 class,但我不知道如何做吧。

检查是否(queryResult.Data.content 是 Usuario)并仅在它为真时才进行转换

否则转换为字符串。

是否每个响应 return 都有不同的 Http 状态代码?我猜你正在 return 从休息 api 中调用 401。如果是这种情况:

然后就可以用一个switch来处理其他的状态码了。

    HttpStatusCode statusCode = queryResult.StatusCode;
    int numericStatusCode = (int)statusCode;

    switch (numericStatusCode)
    {
        case 202:
            dynamic content = queryResult.Data.content;
            Usuario u = content.content; 
            String s = queryResult.Data.estado;
            Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
            break;
        case 401:
            //Deal with the failed login
            break;
    }

最后,您收到错误的原因是您试图将类型为 UsarioResponse 的响应对象转换为 Usario。您需要导航 json 以找到 content.content(如上所示)

我最终通过生成从字典对象到 class 的自定义反射解决了这个问题,也就是说,最后是一个自定义解析器。

我新建了一个classTools并添加了一个转换函数:

public static T CastToObject<T>(IDictionary<string, object> dict) where T : class
{
   Type type = typeof(T);
   T result = (T)Activator.CreateInstance(type);
   foreach (var item in dict)
   {
       type.GetProperty(item.Key).SetValue(result, item.Value, null);
   }
   return result;
 }

并且在 Api 查询中,根据状态代码添加了一个 switch-case:

var queryResult = api.cliente.Execute<Response>(request);

switch(queryResult.StatusCode)
{
    case System.Net.HttpStatusCode.OK:
        Usuario u = Tools.CastToObject<Usuario>((IDictionary<string, object>)queryResult.Data.content);
        String status = queryResult.Data.estado;
        Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
        break;
    case System.Net.HttpStatusCode.NotFound:
            Console.Out.WriteLineAsync($"Login Failed: User does not exists");
            break;
    case System.Net.HttpStatusCode.Unauthorized:
            Console.Out.WriteLineAsync($"Login Failed: Incorrect Password");
            break;
    default:
            Console.Out.WriteLineAsync($"Error when connecting to the API");
            break;
}

此外,我需要处理 content 字段中包含列表的响应,但我认为该过程与此类似:为 content 字段创建自定义解析器并将其投射到我的 class.

派对真的迟到了。当 API 返回与 200 不同的错误结构时,我遇到了类似的问题。我放弃了 RestSharp 的类型化调用并显式反序列化有效负载。

var response = RestClient.Execute<IdamValidationResultApiModel>(request);
if (response.IsSuccessful)
   var t1 = JsonConvert.DeserializeObject<FirstType>(response.Content);
else
   var t2 = JsonConvert.DeserializeObject<SecondType>(response.Content);