我有一个 .NET 类,通过标准 SignalR(C#、ASP.NET、Visual Studio 2013 Community)从 Web 服务器传递到浏览器客户端。
此类包含一个属性,该属性本身就是对同一类的引用(即数据库术语中的外键引用)。
public class Server
{
public Guid ServerId;
public GridLocation Location;
public DateTime DeployedTs;
public Server ParentServer;
}
public class GridLocation
{
public Guid GridLocationId;
public int X;
public int Y;
public Server ServerAtLocation;
}
当我的代码仅发送简单类型(int、String 等)时,一切正常。一旦我放入一个具有本身引用我的 Server 类的属性的类并尝试将其发送到浏览器客户端,我就会收到错误消息:“Newtonsoft.Json.JsonSerializationException:检测到属性“ServerAtLocation”的自引用循环...”
尝试调用 SignalR hub 将数据传递给连接的客户端的代码是:
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<WHub>();
hubContext.Clients.All.serverStatusChangedToClient(myServer);
WHub 是我的 Hub,无需这些复杂的类即可正常工作。
由于这是一个 SignalR 应用程序,我不确定我是否可以控制 JSON 序列化,或者可以吗?如何发送此对象的实例,包括 GridLocation 和 ParentServer 对象的 JSON 表示形式(但对象层次结构中没有比这更深入的深度)?
查看此处的Replacing IJsonSerializer序列化器https://github.com/SignalR/SignalR/wiki/Extensibility,您需要的设置称为ReferenceLoopHandlinghttp://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_ReferenceLoopHandling .htm
尽管我强烈建议不要在应用程序边界之间传递复杂的对象图。
在Microsoft.AspNetCore.Signalr(1.1.0)中的startup.cs中的ConfigureServices方法 您可以执行以下操作
services.AddSignalR().AddJsonProtocol(o =>
{
o.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
现在(2024,.net8),这应该可以解决这个问题:
services.AddSignalR(options => options.EnableDetailedErrors = true).AddJsonProtocol(o =>
{
var jsonSerializerOptions = new System.Text.Json.JsonSerializerOptions();
jsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
o.PayloadSerializerOptions = jsonSerializerOptions;
});