我一直在与此斗争一段时间,我认为是时候寻求帮助了。
我正在使用 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
类(用户)和一个自定义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)且用户存在时,正在解析响应。
但是,当登录不正确时,在“内容”中我将返回一条消息,而不是用户:
{
"estado": "login_incorrecto",
"content": "La contraseña es incorrecta / Password incorrect"
}
因此,如果我在那里使用ResponseUsuario
,则queryResult.Data为null,因为它无法将内容映射到Usuario
类。事实是,如果我不使用ResponseUsuario而是使用Response
类,其中内容变量是类型对象,我无法将其强制转换为Usuario
而我无法处理它。
这是我更了解的Response
类,我应该用它来解决所有问题:
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(或匹配的内容类)?我认为Response
类对于我对API的所有查询都应该是通用的,然后将内容部分转换为它的适当类,但我不知道该怎么做。
答案 0 :(得分:1)
参加聚会真的很晚。当一个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);
答案 1 :(得分:0)
检查if(queryResult.Data.content是否为Usuario)并仅在其为真时进行强制转换
否则转换为字符串。
答案 2 :(得分:0)
每个响应都返回不同的Http状态代码吗?我猜你从你的休息api那里回来了401。如果是这种情况:
然后,您可以使用开关处理其他状态代码。
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(如上所示)
答案 3 :(得分:0)
我终于通过从Dictionary对象生成一个自定义反射到类,即最后一个自定义解析器来解决这个问题。
我创建了一个新类Tools
并添加了一个转换函数:
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
字段创建自定义解析器把它投到我的班上。