【问题标题】:Error while serializing api data : cannot be serialized to JSON because its IsReference setting is 'True'序列化 api 数据时出错:无法序列化为 JSON,因为其 IsReference 设置为“True”
【发布时间】:2014-03-07 07:35:24
【问题描述】:

我已经创建了一个 webApi。当我运行这个 webapi 时,我在浏览器中得到了预期的数据。这是我的 api 获取方法

公共 IEnumerable GetAllProducts()

    {
        return db.products.ToList();
    }

现在我想在我的项目中使用这个 api 服务。为此,我在控制器中编码为

公共视图结果索引()

    {

        var responseStream = requestMethod.GetResponseStream(requestMethod.getRequest("GET", "application/json", string.Format("{0}/api/product/", restService)).GetResponse());

        var products = deSerializeProduct<List<product>>(responseStream) as List<product>;

        return View( products);
    }

要进行序列化,我有一个自定义序列化程序:

public class DefaultSerialization : ISerialization
{
    public string Serialize<T>(object o)
    {
        String json;
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            serializer.WriteObject(stream, (T)o);
            json = Encoding.UTF8.GetString(stream.ToArray());
        }
        return json;
    }
    public object DeSerialize<T>(System.IO.Stream stream)
    {
        var serializer = new DataContractJsonSerializer(typeof(T));


        return serializer.ReadObject(stream);
    }
}

}

但在反序列化时,我在返回序列化程序时出错。ReadObject(stream);如:

“Product”类型无法序列化为 JSON,因为其 IsReference 设置为“True”。 JSON 格式不支持引用,因为没有用于表示引用的标准化格式。要启用序列化,请禁用该类型或该类型的适当父类的 IsReference 设置。

【问题讨论】:

    标签: c# json api serialization


    【解决方案1】:

    有几种可能的想法你可以尝试解决这个问题,主要原因是 EntityFramework(或你的 ORM)与序列化冲突。

    顺便说一句,如果您提供代码,请尝试提供可编译并有意义的代码。由于缺少代码,我无法重现您的问题。如果您可以包含所有代码(甚至是 Visual Studio 项目),我会尝试解决您的问题,而不是基于完全不同的上下文演示解决方案。

    1. 在我看来,您不应该从 API 返回 ORM 对象。而是返回 DataTransferObjects。您从序列化对象中删除实体框架,这样错误可能会消失。

    2. 使用 RestSharp 进行 REST API 调用

    3. 您可以做的是使用以下属性标记您的 Product 实体

      [DataContract(IsReference=false)]

    4. 尝试使用 JSON.NET 吗? http://json.codeplex.com/ 我会使用 JSON.NET 和 DTO 来实现这一点。

    但我不明白的是你想要达到的目标。为什么不简单地对您的 API 进行客户端调用,在这种情况下,我看不到服务器端 API 调用的好处。除非您的 WebApi 托管在不同的环境中,否则从服务器端调用它在任何情况下都没有意义。您的 MVC 项目似乎也引用了您的 ORM 对象层,这又有点奇怪(或者 Product 类不是映射到您的数据库的对象?)

    如果它们在同一台服务器上,以这种方式使用 WebApi 没有任何好处,而是创建一个层来提供您需要的信息,并将其包含在您的 Api 和 Controller 中,这样您的控制器就不需要使用API​​,它可以直接调用其他层。它还删除了服务器端 JSON 反序列化。

    我还注意到您的 API 返回“城市”,而您正在将它们转换为产品,这听起来不是很奇怪吗?

    编辑:工作示例:

    我创建了一个适合我的小型应用程序。示例可在以下网址下载:https://dl.dropboxusercontent.com/u/87239305/WebApi.Example.zip

    我使用 restSharp 在 .NET 中为 DTO 和 EF 相关对象创建 Api 调用。

    非 DTO 示例:

    ApiController 看起来像这样:

    public interface IApiExampleController
    {
        IEnumerable<User> GetAllUsers();
    }
    
    public class ApiExampleController : ApiController, IApiExampleController
    {
        private readonly IEFContext _context;
    
        public ApiExampleController()
        {
            _context = new EFContext();
        }
    
        public IEnumerable<User> GetAllUsers()
        {
            return _context.Users.ToList();
        }
    }
    

    调用 API 的 MVC 控制器如下所示:

    public ActionResult Index()
    {
        var users = GetApiUsers();
        return View(users);
    }
    
    private IList<User> GetApiUsers()
    {
        const string apiBaseUrl = "http://localhost:52812/Api/";
        const string apiSuffix = "ApiExample/GetAllUsers";
    
        var client = new RestClient(apiBaseUrl);
    
        var request = new RestRequest(apiSuffix, Method.GET);
    
        var response = (RestResponse<List<User>>)client.Execute<List<User>>(request);
        return response.Data;
    }
    

    DTO 示例:

    API 控制器:

    public interface IApiDTOExampleController
    {
        IEnumerable<UserDTO> GetAllUsers();
    }
    
    public class ApiDTOExampleController : ApiController, IApiDTOExampleController
    {
        private readonly IEFContext _context;
    
        public ApiDTOExampleController()
        {
            _context = new EFContext();
        }
    
        public IEnumerable<UserDTO> GetAllUsers()
        {
            return _context.Users.Select(x => new UserDTO { Id = x.Id, Name = x.Name }).ToList();
        }
    }
    

    调用该API的代码如下:

    public ActionResult IndexDTO()
    {
        var dtoUsers = GetApiDTOUsers();
        return View(dtoUsers);
    }
    
    private IList<UserDTO> GetApiDTOUsers()
    {
        const string apiBaseUrl = "http://localhost:52812/Api/";
        const string apiSuffix = "ApiDTOExample/GetAllUsers";
    
        var client = new RestClient(apiBaseUrl);
    
        var request = new RestRequest(apiSuffix, Method.GET);
    
        var response = (RestResponse<List<UserDTO>>)client.Execute<List<UserDTO>>(request);
        return response.Data; 
    }
    

    如您所见,DTO 和 EF 实现之间没有太大区别...不过,使用 DTO 可以让您控制调用方需要哪些数据。

    两者都可以正常工作(在我的情况下),因此根据您的产品或城市对象,可能不需要实施 DTO 来消除错误(但我建议您这样做)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2022-10-03
      • 1970-01-01
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多