HttpClient.GetStringAsync 正在返回一个 "Result" 对象?
HttpClient.GetStringAsync is returning a "Result" object?
我正在尝试使用 GetStringAsync 方法从我自己的 API 中检索 JSON 列表。
当我将它 returns 作为 "Result" 对象而不仅仅是字符串时?
然后我尝试将 JSON 数组反序列化为列表但收到错误。
这是 DEBUGGER 中返回的字符串在 HttpCLient.GetStringAsync 中的样子:
"{\"Result\":[{\"id\":92,\"name\":\"Chris Hemsworth\",\"birthDate\":\"1983-8-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":90,\"name\":\"Jennifer Aniston\",\"birthDate\":\"1969-2-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":40,\"name\":\"Edward Norton\",\"birthDate\":\"1969-8-18\",\"role\":\"Writer\",\"originalList\":null}],\"Id\":71,\"Exception\":null,\"Status\":5,\"IsCanceled\":false,\"IsCompleted\":true,\"CreationOptions\":0,\"AsyncState\":null,\"IsFaulted\":false}"
我在尝试将 JSON 对象转换为字符串时遇到的异常:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[BuisnessLogic.Actor]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path 'Result', line 1, position 10.'
更新:
代码如下:
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}"));
演员class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BuisnessLogic
{
public class Actor
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public List<Actor> originalList { get; set; }
public Actor(string name, string birthDate, string role)
{
this.name = name;
this.birthDate = birthDate;
this.role = role;
}
public Actor()
{
}
public override string ToString()
{
return "Person: " + id + "" + name + " " + birthDate + " " + role;
}
}
}
编辑 2:
控制者:
using BuisnessLogic;
using System.Web.Mvc;
namespace WebApplication12.Controllers
{
public class ValuesController : Controller
{
public ILogic _Ilogic;
public ValuesController(ILogic logic)
{
_Ilogic = logic;
}
// GET api/values
public ActionResult GetActors()
{
return Json(_Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
}
}
数据管理class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
namespace BuisnessLogic
{
public class Logic : ILogic
{
static string filePath;
private static ConcurrentDictionary<string, Actor> originalList;
const string BACKUP = @"D:\backup.txt";
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
SaveOriginal();
}
public async static Task<List<Actor>> GetCelebritiesInner()
{
return originalList.Values.ToList();
}
public async Task<List<Actor>> GetAllActorsAsync()
{
return await GetCelebritiesInner();
}
// Try to read the data from the Json and initialize it. if failed , initialize with whatever it got. return
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
public async Task RemoveActorAsync(string name)
{
if (originalList.TryRemove(name, out Actor removedActor))
{
var jsonToWrite = JsonConvert.SerializeObject(await GetCelebritiesInner());
try
{
File.WriteAllText(filePath, jsonToWrite);
}
catch (Exception ex)
{
//Unable to remove due to an error.
}
}
}
public async Task ResetAsync()
{
UpdateFile();
}
//Saving the actor, adding the name as key & object as value.
public static void SaveOriginal()
{
foreach (var currCeleb in ReadActorsFromJson(filePath))
{
originalList.TryAdd(currCeleb.name, currCeleb);
}
}
public static void UpdateFile()
{
File.WriteAllText(filePath, string.Empty);
var text = File.ReadAllText(BACKUP);
File.WriteAllText(filePath, text);
}
}
}
转到uri并获取字符串的更新方法:
public async void update()
{
var b = await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}");
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(b);
foreach (Actor actor in celebrities)
{
actorBindingSource.Add(actor);
}
}
首先将**Result**
替换为Result
。
var stringResult = await HttpCLient.GetStringAsync().Replace("**Result**", "Result");
其次创建 类,它具有与 json 结果相同的属性。
public class JsonResult
{
public List<ResultObject> Result { get; set; }
public int Id { get; set; }
public string Exception { get; set; }
public int Status { get; set; }
public bool IsCanceled { get; set; }
public bool IsComplete { get; set; }
public int CreationOptions { get; set; }
public string AsyncState { get; set; }
public bool IsFaulted { get; set; }
}
public class ResultObject
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public string originalList { get; set; }
}
然后反序列化字符串:
var resultObject = JsonConvert.DeserializeObject<JsonResult>(result);
并且 resultObject
将包含整个结果。
您问题中显示的 JSON 是 Task<T>
的序列化实例,其中包括 Result
、AsyncState
和 IsFaulted
等属性。很明显,这应该是 T
的序列化实例(在您的情况下为 List<Actor>
),这通常意味着某处缺少 await
。
这个 "missing await
" 在你的 ValuesController.GetActors
中,它将 ILogic.GetAllActorsAsync
的结果传递给 Json
。这最终会传入 Task<List<Actor>>
的实例,而不仅仅是 List<Actor>
。为了解决这个问题,使用 await
,像这样:
public async Task<ActionResult> GetActors()
{
return Json(await _Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
这还需要制作 GetActors
async
,正如我在上面所示。
我正在尝试使用 GetStringAsync 方法从我自己的 API 中检索 JSON 列表。 当我将它 returns 作为 "Result" 对象而不仅仅是字符串时?
然后我尝试将 JSON 数组反序列化为列表但收到错误。
这是 DEBUGGER 中返回的字符串在 HttpCLient.GetStringAsync 中的样子:
"{\"Result\":[{\"id\":92,\"name\":\"Chris Hemsworth\",\"birthDate\":\"1983-8-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":90,\"name\":\"Jennifer Aniston\",\"birthDate\":\"1969-2-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":40,\"name\":\"Edward Norton\",\"birthDate\":\"1969-8-18\",\"role\":\"Writer\",\"originalList\":null}],\"Id\":71,\"Exception\":null,\"Status\":5,\"IsCanceled\":false,\"IsCompleted\":true,\"CreationOptions\":0,\"AsyncState\":null,\"IsFaulted\":false}"
我在尝试将 JSON 对象转换为字符串时遇到的异常:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[BuisnessLogic.Actor]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path 'Result', line 1, position 10.'
更新:
代码如下:
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}"));
演员class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BuisnessLogic
{
public class Actor
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public List<Actor> originalList { get; set; }
public Actor(string name, string birthDate, string role)
{
this.name = name;
this.birthDate = birthDate;
this.role = role;
}
public Actor()
{
}
public override string ToString()
{
return "Person: " + id + "" + name + " " + birthDate + " " + role;
}
}
}
编辑 2:
控制者:
using BuisnessLogic;
using System.Web.Mvc;
namespace WebApplication12.Controllers
{
public class ValuesController : Controller
{
public ILogic _Ilogic;
public ValuesController(ILogic logic)
{
_Ilogic = logic;
}
// GET api/values
public ActionResult GetActors()
{
return Json(_Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
}
}
数据管理class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
namespace BuisnessLogic
{
public class Logic : ILogic
{
static string filePath;
private static ConcurrentDictionary<string, Actor> originalList;
const string BACKUP = @"D:\backup.txt";
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
SaveOriginal();
}
public async static Task<List<Actor>> GetCelebritiesInner()
{
return originalList.Values.ToList();
}
public async Task<List<Actor>> GetAllActorsAsync()
{
return await GetCelebritiesInner();
}
// Try to read the data from the Json and initialize it. if failed , initialize with whatever it got. return
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
public async Task RemoveActorAsync(string name)
{
if (originalList.TryRemove(name, out Actor removedActor))
{
var jsonToWrite = JsonConvert.SerializeObject(await GetCelebritiesInner());
try
{
File.WriteAllText(filePath, jsonToWrite);
}
catch (Exception ex)
{
//Unable to remove due to an error.
}
}
}
public async Task ResetAsync()
{
UpdateFile();
}
//Saving the actor, adding the name as key & object as value.
public static void SaveOriginal()
{
foreach (var currCeleb in ReadActorsFromJson(filePath))
{
originalList.TryAdd(currCeleb.name, currCeleb);
}
}
public static void UpdateFile()
{
File.WriteAllText(filePath, string.Empty);
var text = File.ReadAllText(BACKUP);
File.WriteAllText(filePath, text);
}
}
}
转到uri并获取字符串的更新方法:
public async void update()
{
var b = await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}");
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(b);
foreach (Actor actor in celebrities)
{
actorBindingSource.Add(actor);
}
}
首先将**Result**
替换为Result
。
var stringResult = await HttpCLient.GetStringAsync().Replace("**Result**", "Result");
其次创建 类,它具有与 json 结果相同的属性。
public class JsonResult
{
public List<ResultObject> Result { get; set; }
public int Id { get; set; }
public string Exception { get; set; }
public int Status { get; set; }
public bool IsCanceled { get; set; }
public bool IsComplete { get; set; }
public int CreationOptions { get; set; }
public string AsyncState { get; set; }
public bool IsFaulted { get; set; }
}
public class ResultObject
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public string originalList { get; set; }
}
然后反序列化字符串:
var resultObject = JsonConvert.DeserializeObject<JsonResult>(result);
并且 resultObject
将包含整个结果。
您问题中显示的 JSON 是 Task<T>
的序列化实例,其中包括 Result
、AsyncState
和 IsFaulted
等属性。很明显,这应该是 T
的序列化实例(在您的情况下为 List<Actor>
),这通常意味着某处缺少 await
。
这个 "missing await
" 在你的 ValuesController.GetActors
中,它将 ILogic.GetAllActorsAsync
的结果传递给 Json
。这最终会传入 Task<List<Actor>>
的实例,而不仅仅是 List<Actor>
。为了解决这个问题,使用 await
,像这样:
public async Task<ActionResult> GetActors()
{
return Json(await _Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
这还需要制作 GetActors
async
,正如我在上面所示。