Skip to content
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

FormatterNotRegisteredException - Unsure why interface serialization requires custom resolver, when class instance does not. #1708

Open
ProVega opened this issue Nov 29, 2023 · 1 comment

Comments

@ProVega
Copy link

ProVega commented Nov 29, 2023

Apologies, as I feel like I just can't find the documentation, but I need help, I think I need to create a custom resolver but unsure as to WHY and HOW. Here is the error get:

MessagePack.FormatterNotRegisteredException: 'Platform.Data.Models.ICaseInsensitiveDictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Platform.Data.Models.AttributeDetail, Crelate.Platform.Data, Version=23.9.0.0, Culture=neutral, PublicKeyToken=null]] is not registered in resolver: MessagePack.Resolvers.StaticCompositeResolver'

Here is my setup:

StaticCompositeResolver.Instance.Register
(
	NativeDateTimeResolver.Instance,
	// NativeGuidResolver.Instance, Doesn't work? Converts to System.Byte[]
	ContractlessStandardResolver.Instance					
);

// ContractlessStandardResolverAllowPrivate doesn't seem to make a difference
MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard.WithResolver(StaticCompositeResolver.Instance);

Here is my class and interface, which are then used as properties on an object I am tying to serialize. I would expect the reflection-based resolver to just "figure it out" since this is nothing more than a Dictionary.

The reason I am doing this is because, unlike JSON.NET, MessagePack CSharp deserializes the dictionary in a way that RESETS the comparer back to Case Sensitive. The only way I found to fix this was to create a new class (see below) that then calls the base, that way when Message Pack creates the instance of CaseInsensitiveAttributeDetailDictionary it calls the right base constructor.

All was good, I then tried to define an interface for this and expose the property via interface (for Mock) and that's when I started getting the error message.

I think I either need to:

  1. Decorate my interface in some way that I can't figure out
  2. Write a custom resolver, but I honestly don't understand the samples / documentation
  3. Configure my resolvers or interface differently to leverage native functionality of MessagePack.
	public interface ICaseInsensitiveDictionary<TKey, AttributeDetail> : IDictionary<string, AttributeDetail>
	{
	}

	public class CaseInsensitiveAttributeDetailDictionary<TKey, AttributeDetail> : Dictionary<string, AttributeDetail>, ICaseInsensitiveDictionary<TKey, AttributeDetail>
	{
		public CaseInsensitiveAttributeDetailDictionary() : base(StringComparer.OrdinalIgnoreCase)
		{
		}
	}

Thank you.

@AArnott
Copy link
Collaborator

AArnott commented Nov 29, 2023

You cannot deserialize an interface. That's why the DynamicObjectResolver can't handle it automatically and you have to write your own resolver. .NET can instantiate classes, but not interfaces. What concrete type would you have MessagePack instantiate when statically, the type is only an interface?

One way you could workaround this is to use the Typeless resolver, which changes the serialization format to include the concrete type information so that on deserialization it can create an instance of the original type. But this can make your data format more brittle to code changes.

As for the issue with dictionary losing it's comparer, I wonder how Json.NET manages to retain that information in the serialized form. But you can certainly 'fix' this yourself by adding the [MessagePackFormatter] attribute to the property that references a particular dictionary, and in the formatter you provide, provide a class that always creates a dictionary with a particular equality comparer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants