Search code examples
c#mvvmcatel

Catel: How do I know when SavableModelBase.Load fails?


Using Catel 4.4.0.

I let the user browse and load his datafile which is data from a SavableModelBase subclass instance (model ABC) using the Load(stream, XML mode) method. This user made a mistake and loaded the wrong file which is also a SavableModelBase subclass but a totally different model (model XYZ). The code went through the motions of deserializing the data, but of course, none of the properties of the model ABC were found so the instance which was returned (model ABC) contained just the default values of the properties.

I was hoping the Load method would either return a null value or raise an exception. How do I determine the difference between loading an instance of model ABC which is brand new and therefore truly has default property values, and accidentally trying to load model XYZ as model ABC? I didn't see any properties of SavableModelBase which would alert me to the possible mixup.

Is there something built-in to SaveableModelBase which would help me determine a loading error or will I need to come up with some sort of workaround?

If you need more information, please let me know. Thanks!

randy


Solution

  • I decided to create a child class of SavableModelBase with its own Load method. This Load method would first read the root node of the file which have the same name as the name of the class saving the file. If they compare OK, then resume loading with the parent SavableModelBase class Load method. Otherwise, throw an exception. (And I'm ignoring loading with Binary mode at this time.)

    public class LexSavableModelBase<T> : SavableModelBase<T> where T : class
    {
        // SNIP!
    
        public static new T Load(Stream stream, SerializationMode mode)
        {
            Argument.IsNotNull(() => stream);
    
            if (mode == SerializationMode.Xml)
            {
                using (XmlReader xr = XmlReader.Create(stream))
                {
                    xr.MoveToContent();
                    string rootName = xr.LocalName;
                    if (string.Compare(rootName, typeof(T).Name, StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, "Expecting data from Model [{0}], but found Model [{1}] instead.", typeof(T).Name, rootName));
                    }
    
                    // Reset to read from the top.
                    stream.Seek(0, SeekOrigin.Begin);
                }
            }
    
            return SavableModelBase<T>.Load<T>(stream, mode);
        }
    }
    

    I'm sure there is a performance penalty for having to read part of the file twice and I'm only doing enough to meet my small set of scenarios, but it appears to do what I need it to -- detect when the wrong data is being presented for loading. I am only using this on about 4 Models of the 150+ I have in my applications. These are the ones which are saved to and loaded from files on disk by the Customer.

    If you can make any improvements, please do. And let me know if you have any questions.