I have been investigating this exception for a while in my UWP C# project and I am having trouble figuring out exactly what is causing it. I would appreciate a solution, or even some tips on how to troubleshoot beyond what I have done so far.
I recently updated my app to serialize JSON using Newtonsoft.Json instead of System.Text.Json and while it runs, the Debug session breaks later on (VS catches this one, the whole app doesn't crash) due to the exception.
The exception does not occur when I run .Save() after starting the application. This occurs specifically after I upload some images into my app (I'll share some code below) and then click on a button that calls ContinueBtn_Click, which seems related to my exception.
I have been combing through it, but I can't find anything that seems to cause an endless loop. I set breakpoints and outputs in my code, confirming that .Save() as well as ContinueBtn_Click() themselves only run once.
To start, here is the screenshot of the error:
Here is the UserData class. I commented out the References lines in serializerDefault, but the exception occurs even if those are present.
public class UserData
{
public List<CMSession> userSessions { get; set;}
public DatabaseConnection lastDatabaseConnection { get; set;}
[JsonIgnore]
JsonSerializerSettings serializerDefaults = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
//PreserveReferencesHandling = PreserveReferencesHandling.All,
//ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
};
public UserData() { userSessions = new List<CMSession>(); }
/// <summary>
/// Saves the UserData to a serialized user.json file.
/// </summary>
/// <param name="devBreak">If debugging, may provide optional True value to break the debugger prior to save, allowing data manipulation.</param>
public async Task Save(bool devBreak = false)
{
if (devBreak)
{
Debug.WriteLine("Saving with Break Mode. You may manipulate UserData in Immediate Window now, otherwise Continue.");
Debug.Write("");
}
try
{
StorageFile udFile = await ApplicationData.Current.LocalFolder.GetFileAsync(@"UserData\user.json");
var udData = JsonConvert.SerializeObject(this, serializerDefaults);
await Windows.Storage.FileIO.WriteTextAsync(udFile, udData);
Debug.WriteLine("User data was manually saved.");
} catch(Exception ex)
{
if (App.cmDebugger.debug)
{
Debug.WriteLine("Failed to serialize user data to file: " + ex.Message);
}
}
}
}
Here is my page's code-behind method that is calling .Save(), ContinueBtn_Click():
// Clicked after user drops some files into a box, the files are processed then added to pendingInit (a List<WorkingImage>)
private async void IUInit_ContinueBtn_Click(object sender, RoutedEventArgs e)
{
if (pendingInit.Count > 0)
{
for (int i = 0; i < pendingInit.Count; i++)
{
try
{
App.cmSession.IUSession.workAreaImages.Add(pendingInit[i]);
}
catch (Exception ex)
{
if (App.cmDebugger.debug)
{
Debug.WriteLine("Failed to move pending file to work area: " + ex.Message);
try { Debug.WriteLine("Image: " + pendingInit[i].fileName); } catch { }
}
}
}
IUState = DataState.RefreshNeeded;
App.cmSession.IUSession.sessionActive = true;
// This appears to be where the exception occurs.
await App.cmData.Save();
await InitializeIU();
}
else
{
Init_Grid.Visibility = Visibility.Collapsed;
}
IUState = DataState.RefreshNeeded;
}
Here is the JSON that is being generated successfully the first few times .Save() is called:
{
"userSessions": [
{
"LinkedSite": {
"hasContentAccess": true,
"hasMediaAccess": true,
"lastResponse": " (some JSON in here)",
"friendlyName": "website",
"URL": "http://www.google.com/",
"username": "usr",
"status": "connected",
"statusDetail": "Connected to the site without errors.",
"lastConnectionTime": "2023-05-10T15:49:24.0182548-05:00"
},
"IUSession": {
"sessionActive": false,
"workAreaImages": []
}
}
],
"lastDatabaseConnection": null
}
At the risk of making the question a bit long, I'm also providing relevant data structures that are serialized in .Save():
CMSession:
public class CMSession
{
public SiteConnection LinkedSite { get; set; }
public ImageUploaderData IUSession { get; set; }
public CMSession(SiteConnection linkedSite)
{
LinkedSite = new SiteConnection(linkedSite);
IUSession = new ImageUploaderData();
}
}
DatabaseConnection:
public class DatabaseConnection
{
public string dbName = database;
public string dbstate;
public MySqlConnection connection;
}
SiteConnection:
public class SiteConnection
{
public string friendlyName { get; set; }
public string URL { get; set; }
public string username { get; set; }
public string status { get; set; }
public string statusDetail { get; set; }
public DateTime lastConnectionTime { get; set; }
public bool hasContentAccess;
public bool hasMediaAccess;
public object lastResponse;
}
ImageUploaderData:
public class ImageUploaderData
{
public bool sessionActive { get; set; } = false;
public List<WorkingImage> workAreaImages { get; set; }
= new List<WorkingImage>();
}