【问题标题】:Serializing Model using NewtonSoft in WPF Application在 WPF 应用程序中使用 NewtonSoft 序列化模型
【发布时间】:2016-03-06 16:46:07
【问题描述】:

我正在尝试每秒序列化我的模型并将其推送到服务器。我已经设置了一个每秒执行的周期性任务。我调用 SendNewMessage 来执行推送。 从构造函数调用的对 SendNewMessage() 的第一个方法调用运行良好,没有异常或问题。

当异步任务尝试调用 SendNewMessage 时,我得到一个异常并且我的应用程序关闭。这是 NewtonSoft 代码:

String PushModelToServer = JsonConvert.SerializeObject(this, jss); 失败

托管调试助手“FatalExecutionEngineError”检测到一个问题 'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'。 附加信息:运行时遇到致命错误。错误地址位于线程 0x2788 上的 0x71041771。错误代码为 0xc0000005。此错误可能是 CLR 或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

   public class Model : ModelBase
    {
        public Model ()
        {
            PeriodicTask.Run(() => 
            {
                SendNewMessage();
            }, 
            TimeSpan.FromSeconds(1));
            SendNewMessage();
        }
        public void SendNewMessage()
        {
            // Send the message             
            JsonSerializerSettings jss = new JsonSerializerSettings();
            jss.Formatting = Newtonsoft.Json.Formatting.Indented;
            String PushModelToServer = JsonConvert.SerializeObject(this, jss);
            sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));

        }
}

public class PeriodicTask
{
    public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(period, cancellationToken);

            if (!cancellationToken.IsCancellationRequested)
                action();
        }
    }

    public static Task Run(Action action, TimeSpan period)
    {
        return Run(action, period, CancellationToken.None);
    }
}

更多信息按要求: 构造函数中第 10 行的调用运行。序列化第一次工作。由于模型中的数据在变化,我每秒都在推送这个模型来更新服务器。这是异步调用失败。随着时间的推移,模​​型中的数据会发生变化。

【问题讨论】:

  • 嗯,你要序列化的类一定有一些东西,这让序列化器发疯了。
  • 我相信 OP 说调用(第 10 行)有效,但 lambda 内第 7 行的调用无效。如果该类用正确的属性装饰,它应该可以正常工作。也许 OP 可以澄清示例以显示哪个调用适用于评论,并可能用更多细节扩展问题。
  • @KoryGill 你是对的。我应该用哪些属性“装饰”它?我以前没有这样做过。我只想要基本是字符串、浮点数和布尔基类型的公共属性。

标签: c# wpf serialization thread-safety


【解决方案1】:

您可以使用[IgnoreDataMember] 来避免序列化不应包含的属性。

以下代码适用于我的应用程序,希望能帮助您找到适合您应用程序的解决方案。

我希望您上面显示的代码是您真实代码的 sn-p,因为 1 秒计时器、重入等存在一些潜在问题。不要在模型构造函数中执行此计时器,而是考虑将其移动到另一个函数/类,并从您稍后设置的附加呼叫中设置计时器/呼叫......再次,只是一些关于达成良好模式的建议。在这里做更多的研究......

这是我获取数据的方式,您想要的 PushModelToServer

public class BackupData
{
    public List<Vehicles> Vehicles { get; private set; }
    public List<FuelStops> FuelStops { get; private set; }

    public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
    {
        Vehicles = vehicles;
        FuelStops = fuelStops;
    }

    public string ToJson(Formatting formatting = Formatting.None)
    {
        var json = JsonConvert.SerializeObject(this, formatting);
        return json;
    }

    public static BackupData FromJson(string jsonBackupData)
    {
        var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
        return data;
    }
}

这是我的一个课程的 sn-p:

[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
    private string id;
    public string Id
    {
        get { return id; }
        set
        {
            if (id != value) { id = value; NotifyPropertyChanged(); }
        }
    }

    private string vehicleName;
    public string VehicleName
    {
        get { return vehicleName; }
        set
        {
            if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
        }
    }

    public override string ToString()
    {
        return VehicleName;
    }

    [IgnoreDataMember]
    public UpdateState UpdateState { get; set; }
    ....

这是我获取数据的方式,以便我可以在任何我想要的地方使用它:

#if WINDOWS_PHONE_APP
    private void OnExecuteBackup(SettingsPage obj)
    {
#else
    private async Task<bool> OnExecuteBackup(SettingsPage obj)
    {
#endif
        var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
        ...
        await SaveBackupFile(file, backupData);
        ...


public class JournalModel
{
    ...
    public BackupData GetBackupData()
    {
        var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
        return data;
    }
    ...

祝你的项目好运。

【讨论】:

  • 我在一些复杂对象上使用了参数:[JsonIgnore],现在效果很好! :)
【解决方案2】:

嗯,你要序列化的类肯定有一些东西,这会让序列化器发疯。也许不是序列化'this'你应该尝试序列化一个实际的'DataObject'——可以序列化的东西,不包含对定时器、任务等的引用。

【讨论】:

  • 是的,这是可能的。不过这需要一些工作。
猜你喜欢
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多