如何解决.NET MAUI中反序列化JSON时的InvalidOperationException?
我正在开发一个.NET MAUI迷你银行应用,点击「登录」或「注册」按钮时会从JSON文件加载客户数据。当Customer没有关联账户时反序列化正常,但添加BankAccount到JSON文件后,反序列化时抛出InvalidOperationException。
错误信息
System.InvalidOperationException
HResult=0x80131509
Message=Each parameter in the deserialization constructor on type 'ReadOnlyBankingSystem.Models.BankAccount' must bind to an object property or field on deserialization. Each parameter name and type must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The name match can be case-insensitive.
Source=System.Text.Json
相关代码
Customer类
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Text.Json.Serialization; namespace ReadOnlyBankingSystem.Models { public class Customer { public string Username { get; set; } public string Password { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public string Address { get; set; } public DateOnly DateOfBirth { get; set; } public ObservableCollection<BankAccount> Accounts { get; set; } public Customer(string username, string password, string firstName, string lastName, string email, string address, DateOnly dateOfBirth) { this.Username = username; this.Password = password; this.FirstName = firstName; this.LastName = lastName; this.Email = email; this.Address = address; this.DateOfBirth = dateOfBirth; this.Accounts = new ObservableCollection<BankAccount>(); } } [JsonSerializable(typeof(Dictionary<string, Customer>))] internal sealed partial class CustomerContext : JsonSerializerContext { } }
BankAccount类
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Text.Json.Serialization; namespace ReadOnlyBankingSystem.Models { public class BankAccount { [JsonInclude] public readonly Guid AccountId; [JsonInclude] public readonly DateTime DateCreated; [JsonInclude] public readonly int PIN; public decimal Amount { get; set; } public ObservableCollection<Transaction> Transactions { get; set; } public BankAccount(Guid accountId, DateTime dateCreated, int pin, decimal initialAmount) { AccountId = accountId; DateCreated = dateCreated; Amount = initialAmount; PIN = pin; Transactions = new ObservableCollection<Transaction>(); } } }
序列化/反序列化函数
public async Task<Dictionary<string, Customer>> ReadFromJsonFile(string filename) { string appDataFilePath = GetAppDataFilePath(filename); using var stream = File.OpenRead(appDataFilePath); using var reader = new StreamReader(stream); var contents = await reader.ReadToEndAsync(); var customerDictionary = JsonSerializer.Deserialize(contents, CustomerContext.Default.DictionaryStringCustomer); return customerDictionary; } public async Task WriteToJsonFile(string filename, Dictionary<string, Customer> customerData) { string appDataFilePath = GetAppDataFilePath(filename); using var stream = File.OpenWrite(appDataFilePath); using var writer = new StreamWriter(stream); var options = new JsonSerializerOptions { WriteIndented = true }; var contents = JsonSerializer.Serialize(customerData, options); await writer.WriteAsync(contents); }
问题根源在于BankAccount的构造函数参数与类中字段/属性不匹配,且反序列化未配置包含字段的选项。具体修复步骤如下:
步骤1:调整BankAccount构造函数参数名
将构造函数中的initialAmount改为amount,让参数名与Amount属性名匹配,保证反序列化时能正确绑定:
public BankAccount(Guid accountId, DateTime dateCreated, int pin, decimal amount) { AccountId = accountId; DateCreated = dateCreated; Amount = amount; PIN = pin; Transactions = new ObservableCollection<Transaction>(); }
步骤2:配置JsonSerializerContext启用字段支持
修改CustomerContext,添加JsonSourceGenerationOptionsAttribute开启IncludeFields,并显式添加BankAccount的序列化支持:
[JsonSourceGenerationOptions(IncludeFields = true)] [JsonSerializable(typeof(Dictionary<string, Customer>))] [JsonSerializable(typeof(BankAccount))] internal sealed partial class CustomerContext : JsonSerializerContext { }
步骤3:统一序列化与反序列化的配置
在WriteToJsonFile中使用CustomerContext的内置选项,避免序列化和反序列化配置不一致:
public async Task WriteToJsonFile(string filename, Dictionary<string, Customer> customerData) { string appDataFilePath = GetAppDataFilePath(filename); using var stream = File.OpenWrite(appDataFilePath); await JsonSerializer.SerializeAsync(stream, customerData, CustomerContext.Default.DictionaryStringCustomer); }
可选替代方案(无需修改参数名)
如果不想调整构造函数参数名,可以给参数添加JsonPropertyName特性指定对应属性名:
public BankAccount(Guid accountId, DateTime dateCreated, int pin, [JsonPropertyName("Amount")] decimal initialAmount) { AccountId = accountId; DateCreated = dateCreated; Amount = initialAmount; PIN = pin; Transactions = new ObservableCollection<Transaction>(); }
注意:如果
Transaction类也存在只读字段或构造函数绑定问题,需要执行同样的修复操作。
内容的提问来源于stack exchange,提问作者Arturo Girona

