Skip to content

Enable serialization of POCO types via MobileFormatter #2148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rockfordlhotka opened this issue Mar 11, 2021 · 10 comments · Fixed by #4024
Closed

Enable serialization of POCO types via MobileFormatter #2148

rockfordlhotka opened this issue Mar 11, 2021 · 10 comments · Fixed by #4024

Comments

@rockfordlhotka
Copy link
Member

rockfordlhotka commented Mar 11, 2021

There are times when it would be nice to include a simple POCO style type in an object graph. Right now the most basic serializable type is MobileObject, which requires manual work to serialize things like fields.

There are several thoughts to consider. One is documented here, which is to use a base class. Another would be to have MF trigger on an attribute that delegates to an arbitrary "serializer" that returns/accepts a byte[] representing that class. Yet another would be to pass in a list of serializers to MobileFormatter (via DI), where each of these serializers would have the opportunity to say that they can serialize a given type that would otherwise not be serialized by MF.

MobilePoco base class

It is possible to create a MobilePoco type that uses reflection to get/set property and field values as needed by the MobileFormatter. This should be added to the Csla.Core namespace.

Here's a quick prototype of the idea:

using System;
using Csla.Serialization.Mobile;

namespace ConsoleApp3
{
  [Serializable]
  public abstract class MobilePoco : IMobileObject
  {
    void IMobileObject.GetChildren(SerializationInfo info, MobileFormatter formatter)
    {
    }

    void IMobileObject.SetChildren(SerializationInfo info, MobileFormatter formatter)
    {
    }

    private const System.Reflection.BindingFlags bindingFlags =
      System.Reflection.BindingFlags.Public |
      System.Reflection.BindingFlags.NonPublic |
      System.Reflection.BindingFlags.Instance;

    void IMobileObject.GetState(SerializationInfo info)
    {
      var fields = this.GetType().GetFields(bindingFlags);
      foreach (var item in fields)
        info.AddValue(item.Name, item.GetValue(this));
      var properties = this.GetType().GetProperties(bindingFlags);
      foreach (var item in properties)
        info.AddValue(item.Name, item.GetValue(this));
    }


    void IMobileObject.SetState(SerializationInfo info)
    {
      var fields = this.GetType().GetFields(bindingFlags);
      foreach (var item in fields)
        item.SetValue(this, info.GetValue<object>(item.Name));
      var properties = this.GetType().GetProperties(bindingFlags);
      foreach (var item in properties)
        item.SetValue(this, info.GetValue<object>(item.Name));
    }
  }
}

SerializeUsing attribute

[SerializeUsing(typeof(MySerializer))]
public class MyPoco {}

Presumably the MySerializer type would implement Csla.Serialization.ISerializationFormatter.

Custom Serializer List

Regarding the DI injection of a list of serializers, those serializers might implement an interface like this:

public interface ISerializer
{
    bool SerializesType(Type type);
    byte[] Serialize(object obj);
    object Deserialize(byte[] data);
}

When MF encounters a type it wouldn't otherwise be able to serialize, it would go through the list of custom serializers, calling SerializesType on each. If one returns true, then it would be used to serialize the object in question.

This technique could be used to generalize the way ClaimsPrincipal is currently handled. Right now it is hard-coded into MF as an exception, but that implementation could be moved out to a custom serializer instead.

@rockfordlhotka rockfordlhotka changed the title Add MobilePoco to Csla.Core Enable serialization of POCO types via MobileFormatter Mar 12, 2021
@angtianqiang
Copy link

GOOD

@bradtwurst
Copy link
Contributor

bradtwurst commented Jul 21, 2021

As I am attempting to migrate away from WCF and deal with a lot of POCO objects, I found my way here.

I found MobileFormatter very tough (frustrating) to deal with as it is sealed, locked-down, and is currently hard-coded in many of the portal implementations (although I do see that this last issue has changed in main branch).

While this may not be the ultimate solution, would it make sense to have an OnSerializing/Deserializing method hooks that could be utilized to allow the app developer to inherit from MF and tweak the logic.

I know that this wouldn't solve all the things, but it is a fairly straight-forward pattern that was used in other parts of the framework and it could be implemented in the current v5 release without breaking all the things.

If it sounds like an acceptable strategy, I'd be willing to invest some effort into this area as it is directly affecting my current focus.

James

@rockfordlhotka
Copy link
Member Author

@bradtwurst let's have that discussion here: #2386 - so as not to dilute this particular backlog item, which is more focused on a specific issue.

@TheCakeMonster
Copy link
Contributor

I have been continuing to think about the addition to support custom serializer types; I hadn't forgotten - I just chose another route for the serialization of POCOs. I am particularly aware of the hard-coding in MobileFormatter associated with CslaClaimsPrincipal, and I thought the support for custom serializers would alleviate that. However, I then started to wonder if there was a simpler approach to that solution; if we implemented IMobileObject on CslaClaimsPrincipal that might negate the need for a custom serializer for it. If I'm right then the need for a significant change to the framework might feel less appropriate again.

Is there any reason why implementing IMobileObject on CslaClaimsPrincipal doesn't remove the need for the custom code which handles it in the MobileFormatter class? The section of code to which I refer is in MobileFormatter.cs, around line 151, as well as the equivalent in the Deserialize method, around line 265.

@TheCakeMonster
Copy link
Contributor

TheCakeMonster commented Oct 2, 2021

Even if we resolve the problem with CslaClaimPrincipal as I have described, there is one remaining issue - the custom handling of System.Security.Claims.ClaimsPrincipal.

We can't resolve ClaimsPrincipal through the addition of a SerializeUsing attribute; we don't have control over the source code of that type (nor would we want to add the assembly reference that it would require.)

Using DI to manage custom serializers is an alternative that would work for a built in type. The approach I considered was to query DI to ask if a serializer is registered for a type. Sadly the ability to query DI has only just been added as part of .NET 5 or 6, meaning this approach wouldn't work for older runtimes.

I think that leaves registering a list of custom serializers as the most viable option to resolving the problem with ClaimsPrincipal.

@rockfordlhotka
Copy link
Member Author

@TheCakeMonster there are some warnings during build relative to the new generator code:

2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoNonSerializedAttribute.cs(19,10,19,36): warning CS1591: Missing XML comment for publicly visible type or member 'AutoNonSerializedAttribute.AutoNonSerializedAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializableAttribute.cs(20,10,20,35): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializableAttribute.AutoSerializableAttribute()'
2>E:\src\rdl\csla\Source\Csla\Serialization\AutoSerializedAttribute.cs(20,10,20,33): warning CS1591: Missing XML comment for publicly visible type or member 'AutoSerializedAttribute.AutoSerializedAttribute()'

@TheCakeMonster
Copy link
Contributor

Oh, OK. Yes, I'll have a look at that. I didn't spot those, sorry. I didn't think of adding documentation to them, as they are not really visible for the documentation to be of benefit.

As an aside, you can now see the generated output if you have a special workload installed.

http://stevetalkscode.co.uk/debug-source-generators-with-vs2019-1610

@TheCakeMonster
Copy link
Contributor

I've created issue #2659 to track the one remaining area of concern - that the source generator creates build warnings (and probably doesn't work) for libraries that target anything other than .NET Standard. This allows easier tracking of that problem.

With that separated out, this task can be closed.

@rockfordlhotka
Copy link
Member Author

Related to #2531.

@rockfordlhotka rockfordlhotka self-assigned this Jun 14, 2024
@rockfordlhotka rockfordlhotka moved this to In Progress in CSLA Version 9.0.0 Jun 14, 2024
rockfordlhotka added a commit that referenced this issue Jun 20, 2024
* #2531 Initial changes to implement IMobileSerializer concept

* #2531 Maintain Serialization configuration for custom formatters

* Use modern namespace technique

* Fix comment

* #2531 Initial implementation of deserialization

* Resolve build warning

* #2531 Rework how mobile formatter config works

* #2531 Custom serializer now works with ClaimsPrincipal

* #2531 Remove obsolete CslaClaimsPrincipal type

* Clean up ctor and application context

* #2531 Put ClaimsPrincipalSerializer into core framework

* #2531 Add custom serializer tests

* #2531 Updates based on PR feedback

* Fix comments

* #2531 Move serialzation formatter config to be instance not static

* Clean up what were static methods to work correctly now

* #2531 Allow unknown types to fall through FieldDataManager as "children"

* #2531 Ensure native types are handled correctly

* #2531 Update tests

* #2531 Use a func to determine if a type can be handled by a serializer

* #2531 Add test using CanSerialize

* #2531 Rework TypeMap to use generics for type safety and readability

* #3363 Add test for DateTime.Kind serialization

* #1877 Add implementation of ClaimsPrincipal serialization for .NET Framework

* Fix build warning

* #2148 Add Json-based PocoSerializer for simple types

* #2531 Update method name

* #2531 Add and use MobileFormatterException

* #2531 Update implementation and property scopes

* #2531 Make type internal

* Update tests

* #2531 Use DI to get the ISerializationFormatter service

* #2531 Remove SerializationFormatterFactory type

* #2531 Remove OriginalType

* Remove commented code

* #2531 Clean up code

* #2531 Fix expected exception type

* Remove obsolete compiler conditionals

* #3871 Updated release notes

* Add `dev/` prefix to working branch names

* #2531 Code cleanup and improvement based on PR review

* #2531 Make MobileFormatterOptions a service
@github-project-automation github-project-automation bot moved this from In Progress to Done in CSLA Version 9.0.0 Jun 20, 2024
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

Successfully merging a pull request may close this issue.

4 participants