Caliburn.Micro Serialization Issue When Implementing Propertychangedbase

caliburn.micro serialization issue when implementing PropertyChangedBase

You need to add the [DataContract] attribute to your Person class and the [DataMember] attribute to every property and field you wish to serialize:

[DataContract]
public class Person : PropertyChangedBase
{
[DataMember]
public int Id { get; set; }

private string _firstName;

[DataMember]
public string FirstName { get; set; }
}

You need to do this because the caliburn.micro base class PropertyChangedBase has the [DataContract] attribute:

namespace Caliburn.Micro {
[DataContract]
public class PropertyChangedBase : INotifyPropertyChangedEx
{
}
}

But why should this be necessary? In theory, the presence of the DataContractAttribute applied to the base class should not affect your derived Person class, because DataContractAttribute sets AttributeUsageAttribute.Inherited = false:

[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Enum, Inherited = false, 
AllowMultiple = false)]
public sealed class DataContractAttribute : Attribute

However, HttpClientExtensions.PostAsJsonAsync uses the default instance of JsonMediaTypeFormatter, which by default uses the Json.NET library to perform serialization. And Json.NET does not respect the Inherited = false attribute of DataContractAttribute, as is explained here

[Json.NET] detects the DataContractAttribute on the base class and assumes opt-in serialization.

(For confirmation see Question about inheritance behavior of DataContract #872 which confirms this behavior of Json.NET continues to be as intended.)

So you need to add those attributes after all.

Alternatively, if you do not want to have to apply data contract attributes all over your derived classes, you could switch to DataContractJsonSerializer following the instructions here: JSON and XML Serialization in ASP.NET Web API:

If you prefer, you can configure the JsonMediaTypeFormatter class to use the DataContractJsonSerializer instead of Json.NET. To do so, set the UseDataContractJsonSerializer property to true:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;

Don't serialize Caliburn.Micro IsNotifying property

In your SerializeObject<T> method, try this:

var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(PropertyChangedBase), "IsNotifying", new XmlAttributes
{
XmlIgnore = true,
});
var xmlSerializer = new XmlSerializer(toSerialize.GetType(), overrides);

The XmlAttributeOverrides type lets you customize everything that can be done using xml serializer attributes - but at runtime. I was amazed when I found out.

Further reading: .NET Framework Documentation

Custom serialization in Caliburn.Micro 1.1

I don't know if this is the right path, but it works; here is a code sample:

Property(x => x.Strokes).InPhoneState().RestoreAfterViewReady().Configure(x =>
{
x.Save = SaveStrokes;
x.Restore = RestoreStrokes;
});

with their implementations like:

void SaveStrokes(BoardViewModel vm, Func<string> serialize, StorageMode nMode)
{
IsolatedStorageSettings.ApplicationSettings[vm.DisplayName + "ThePropertyKey"] =
// ...get data from vm and serialize
}

and conversely:

void RestoreStrokes(BoardViewModel vm, Func<string> serialize, StorageMode nMode)
{
// use IsolatedStorageSettings.ApplicationSettings[vm.DisplayName + "ThePropertyKey"]
// to check if the key exists, and if it is there get the serialized data and deserialize
}

As for strokes, I'm using my own serialization class as my usual tool for this purpose (SharpSerializer) seems having issues in restoring (it throws an ambiguous match reflection exception).

Is JSON.NET's caching strategy messing with my development cycle?

I'm trying to add a field to an existing datacontract in our system. Json.NET supports data contracts, and data contract serialization is opt-in:

Apply the DataContractAttribute attribute to types (classes, structures, or enumerations) that are used in serialization and deserialization operations by the DataContractSerializer...

You must also apply the DataMemberAttribute to any field, property, or event that holds values you want to serialize. By applying the DataContractAttribute, you explicitly enable the DataContractSerializer to serialize and deserialize the data.

Thus if your model is marked with [DataContract], then you need to mark your new member with [DataMember]:

[DataContract]
public class Model : SomeBaseClass
{
[DataMember]
public string NewProperty;
}

Note that, even if your Model class is not marked with [DataContract], Json.NET still requires that serializable members be marked with [DataMember] as long as some base class of Model is marked with [DataContract]. For details see caliburn.micro serialization issue when implementing PropertyChangedBase.

Caliburn Micro Changes from Version 1.1 to 1.5.1?

This is taken from each of the release's changes.txt:

1.2

  • Improvements to EventAggregator to improve testability and re-use apart from the full Caliburn.Micro framework.
  • Enabled basic child containers for the SimpleContainer.
  • Some improvements to the nuget install script.
  • Improvements and bug fixes for View/ViewModel name resolution.
  • Fixed some NRE's in the new UriBuilder. NO explicitly throws if it cannot locate the view.
  • Improved logging around searched for Views/ViewModels.
  • Fixed bugs with the WP7 version of Screen.OnViewReady. It now works consistently.
  • Improvements to PropertyChangedBase and BindableCollection to better support serialization.
  • Moved IsInDesign mode out of Bootstrapper and into the Execute class.
  • Added WP7 platform abstractions for vibration and sound effects, including enabling the window manager to play sounds when showing a custom modal dialog.
  • Fixed some bugs in the WindowManager related to bubbling actions.
  • Fixed some issues with the WPF navigation service.
  • Minor refactoring to enable the new "feature packages".

1.3

  • Improved serialization of PropertyChangedBase and BindableCollection
  • Enabled the WP7 UriBuilder to actually build a Uri without navigating.
  • Added SetUIThreadMarshaller method to Executor to allow customization of the framework's default thread marshalling behavior.
  • Added optional settings parameters to all window manager apis.
  • Changed FrameAdapter to inject query string parameters into the ViewModel before the conventional databinding takes place.
  • Added a new WinRT project. WinRT now supports Execute, BindableCollection, PropertyChangedBase, ExtensionMethods, EventAggregator and SimpleContainer.
  • Fixed some WPF bugs in Screen
  • Vast improvements and API enhancements to ViewModelLocator and ViewLocator for easier customization of location conventions.
  • Fixed a potential memory leak in coroutines that are cancelled and re-used.
  • Enabled design-time application of convention bindings (preliminary support). To turn this feature on, set the Bind.AtDesignTime attached property to true for your view. If you are using blend's design-time data generation, you can optionally replace ViewLocator.ModifyModelTypeAtDesignTime to perform custom mapping to views. It shouldn't be needed though.
  • Turned ConventionManager.ConfigureSelectedItem into a delegate to allow customizations.
  • Added ConventionManager.ConfigureSelectedItemBinding delegate aimed to allow the inspection of the proposed binding and its customization or rejection.
  • Added Support for WP7 Mango
  • Added Support for Silverlight 5
  • Various improvements made to the NavigationService; improvements to navigation away, tombstoning, etc.
  • Fixed some WPF bugs with TabControl
  • Some improvements to integration between the tombstoning mechanism and the IoC container.
  • The Application property of the Bootstrapper is no longer globally available, to help prevent misuse.
  • Some breaking changes in ConventionManager API related to bug fixes in ItemsControl conventions.
  • Enabled overriding of default services in PhoneContainer
  • Assemblies are now marked as CLSCompliant.
  • Added a new Func to ViewLocator called DeterminePackUriFromType. This function maps a View Type to pack Uri for use in navigation scenarios. Since there is no way to reliable way to determine the Uri from a type, a default implementation is provided which should work for most cases, but can be replaced for other scenarios. This function is used internally by the WP7 UriBuilder.
  • Updated the SL5 build to use the new native UpdateSourceTrigger.
  • Enabled ValidatesOnExceptions when conventional validation is turned on for a binding.
  • Fixed a certain long-standing bug which caused problems when conventions were applied via the Bind.Model property inside of a virtualizing control with container recycling enabled. This may have fixed some other intermitent issues related to the Bind.Model property as well.

1.3.1

  • Switching to Semantic Versioning.
  • Added some exception handling for design time bootstrapper operations.
  • Added a custom converter to the MessageBinder so that we can handle converting to DateTime from string.

1.4

This includes no changes.txt, so the best I could find was:

This version includes many bug fixes across all platforms, improvements to nuget support and...the biggest news of all...full support for both WinRT and WP8.

Deserializing object that inherits from ReactiveObject from Json does not work

To properly serialize ReactiveObjects you should use the DataContract attribute of the System.Runtime.Serialization namespace. Then mark the members you'd like to save with the DataMember attribute, and the ones you don't want to save with the IgnoreDataMember attribute.

So in your case, something like this:

[DataContract]
class ReactiveProfile : ReactiveObject
{
[IgnoreDataMember]
private string _name;

[DataMember]
public string Name
{
get => _name;
set => this.RaiseAndSetIfChanged(ref _name, value);
}
}

Here's one of Paul's old example usages on Github: link

And a documentation link for data persistence: link

I ran the code you provided with this change, and it works as expected. Let me know if you have any questions.



Related Topics



Leave a reply



Submit