I'm working on an ActivityPub implimentation in c#, and sometimes links are "strings" like a url link, and sometimes links are objects with a Link sub-type. (Link : Entity)
I'm wondering if there's a possible way to use System.Text.Json to serialize a Link object as a string if a certain set of conditions are true (just write one string to the writer), and write the whole default object to the writer if the condition is not true.
I have tried following this solution: How to use default serialization in a custom System.Text.Json JsonConverter?, which still works on the code fiddle, but does not work for my implimentation and I'm not too sure why.
Does anyone know how I might debug this, or a better way to go about making sure Link : Entity
objects can serialize into strings on occasion?
With that I get the following error:
(in this case I have even tried to add the fetched default ctor to the modifiedOptions) Reguardless, it says that there's no data mapped for the Link class. I have also tried adding the JsonSerializeable attribute directly to the Link class.
The Error:
Metadata for type 'ActivityPub.Types.Link' was not provided to the serializer. The serializer method used does not support reflection-based creation of serialization-related type metadata. If using source generation, ensure that all root types passed to the serializer have been indicated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.
My base code library: https://github.com/Meep-Tech/ActivityHub.Net/tree/collapse_links_during_serialization
The test code:
static void Main(string[] args) {
Settings.DefaultContext = new Link("ActivityPub.Net.Testing");
var testObject = new Object {
Type = "Test",
At = new Link("/terry") {
Rels = new string[] {
"test",
"test2"
}
},
Attribution = "/meep",
Audience = new Link("/all") {
Rel = "test"
}
};
string json = testObject
.Serialize();
System.IO.File.WriteAllLines(
"test.json",
new[] { json }
);
Object @object = json.DeSerializeEntity<Object>();
System.IO.File.WriteAllLines(
"test1.json",
new[] { @object.ToString() }
);
}
In my original version of
DefaultConverterFactory<T>
, I cached the default converter because, in its documentation How to write custom converters for JSON serialization (marshalling) in .NET, Microsoft recommends, when serializing a complex object, to cache any required converters for performance reasons:However, this has proven problematic for several reasons:
When serializing a polymorphic value with a declared type of
object
, a non-functional converter is returned byGetConverter()
.When serializing numeric values, the converter returned ignores the
NumberHandling
setting.And now it appears you may have encountered a third problem: when using compile-time serializer source generation, the converter returned may not work.
That is enough problems to warrant ignoring Microsoft's recommendation. Simply
DefaultConverter<T>
as follows:Then, in any classes derived from
DefaultConverterFactory<T>
such as this one here, remove the final parameterJsonConverter<T> defaultConverter
fromRead()
andWrite()
, and your code should now work.(Incidentally, you seem to be using
[JsonSerializable(typeof(Link))]
wrongly. You are applying it to your model classLink
but, according to the docs, it should be applied to some subclass ofJsonSerializerContext
for your model -- not the model itself.)