0
votes

In my Silverlight/XNA app/game I save and load a custom class Level.cs to Isolated Storage. I serialize and deserialize the level using SharpSerializer. The code below is combined from several tutorials on saving and serializing. The code works most of the time, but if I save and load a level repeatedly, usually 2 or 3 times, I will get an exception thrown in the Load() method. I have been unable to track down the cause of this exception. Right now I am handling it by restarting the level from the default XML file when this occurs.

My Questions:

1.) Do you know what is causing my exception, and how can I fix it?

2.) Are there any additional details in the Exception that I am catching that might help me track down what is causing this?

3.) Is there a better method for structuring this code? Most examples I have found use "using" statements. Is there an advantage to that method that might help me here?

Additional Details:

The strange part is that if I quit the app without saving and then run the app again, it will successfully load the Isolated Storage file that it just failed to load. This leads me to believe that the save file is not corrupted, but that I am likely not disposing of some resources properly each time I save/load and as those resources build up during an instance of running the app, it eventually causes this issue.

When the exception is thrown, it is always thrown by this line in the Load() method:

LoadStream = LoadStorage.OpenFile(loadName, FileMode.Open);  

The exception description is {"Operation not permitted on IsolatedStorageFileStream."}. Are there any other relavant details in the exception that I should look for? The inner exception could not be read.

My method for saving:

public void Save()      
{      
    IsolatedStorageFile SaveStorage = null;      
    SaveStorage = IsolatedStorageFile.GetUserStoreForApplication();      
    IsolatedStorageFileStream SaveStream = null;      
    string saveLName = "levelSave_" + currentLevel.info.number + ".XML";      

    if (SaveStorage.FileExists(saveLName))      
    {      
        SaveStorage.DeleteFile(saveLName);      
    }      

    try     
    {      
        SaveStream = SaveStorage.CreateFile(saveLName);      
        var serializer = new SharpSerializer();      
        serializer.Serialize(currentLevel, SaveStream);      

        saveState = SaveState.Successful;      
    }      
    catch (Exception ex)      
    {      
        saveState = SaveState.Failed;      
    }      
    finally     
    {      
        if (SaveStream != null)      
        {      
            SaveStream.Close();      
            SaveStream.Dispose();      
        } if (SaveStorage != null)      
        {      
            SaveStorage.Dispose();      
        }      
    }      
}  

My method for loading:

public Level LoadLevel(int levelNumber)   
{   
    IsolatedStorageFile LoadStorage;   
    LoadStorage = IsolatedStorageFile.GetUserStoreForApplication();   
    Level tmpLevel;   
    string loadName = "levelSave_" + levelNumber + ".XML";   

    if (LoadStorage.FileExists(loadName))   
    {   
        IsolatedStorageFileStream LoadStream = null;   
        try  
        {   
            LoadStream = LoadStorage.OpenFile(loadName, FileMode.Open);   
            var serializer = new SharpSerializer();   
            tmpLevel = (Level)serializer.Deserialize(LoadStream);   
        }   
        catch (Exception ex)   
        {   
            tmpLevel = LoadLevelXML(levelNumber);   
            // Level failed to load from save,   
            // restart unsaved level from beginning   
        }   
        finally  
        {   
            if (LoadStream != null)   
            {   
                LoadStream.Close();   
                LoadStream.Dispose();   
            }   
            if (LoadStorage != null)   
            {   
                LoadStorage.Dispose();   
            }   
        }   
    }   
    else  
    {   
        tmpLevel = LoadLevelXML(levelNumber);   
        // Level save file not found,   
        // restart unsaved level from beginning   
    }   
    return tmpLevel;   
}  

I believe this code is probably unnecessary in the Save() method. I just added it to make sure overwriting a file was not the problem.

if (SaveStorage.FileExists(saveLName))      
{      
    SaveStorage.DeleteFile(saveLName);      
}  

I also believe that this code in both methods is unnecessary, but again, I added it to ensure that the "storage" floating around was not the issue.

if (LoadStorage != null)      
{      
    LoadStorage.Dispose();      
}

The exception was thrown before I added either of those segments of code.

3
What kind of code/interaction calls Save? The exception can occur if you happen to press a button twice, and as such attempt to save while the previous save action is still in action.Claus Jørgensen
Save is called by a button press. I just added the check to see if saveState is currently saving. private void SaveQuitButton_Click(object sender, RoutedEventArgs e) { if (saveState != SaveState.Saving) { Save(); NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative)); } } Additionally I added this line to set the saveState to be saving at the beginning of the try in the Save method. try { saveState = SaveState.Saving; SaveStream = SaveStorage.CreateFile(saveLName); }Jared Greiner
Well, that formating completely failed.Jared Greiner
It's possible that Save and Load method executes simultaneously? Try use lock statement to make it thread-safeKu6opr
Out of curiosity, how large is the file? IsolatedFileStorage only supports a small amount of data by default. You also should use a using-statement instead of rolling your own with a try...finally.user7116

3 Answers

0
votes

I have a feeling that blocking IO operations may throw an IllegalOperationException if performed on the UI thread.

Have you tried performing your serialisation on a background thread (for example, using BackgroundWorker)?

0
votes

Now, just for kicks, give this a spin:

lock (SaveStorage)
{
    if (SaveStorage.FileExists(saveLName))
    {
        SaveStorage.DeleteFile(saveLName);
    }
}
0
votes

You should be using Mutex concept..refer these..

http://msdn.microsoft.com/en-us/library/ff402541(v=vs.92).aspx http://forums.create.msdn.com/forums/p/94965/568077.aspx