Skip to content
Dorin Mocan edited this page Dec 13, 2022 · 13 revisions

Welcome to the SerializationInterceptor wiki!

Nuget link: www.nuget.org/packages/SerializationInterceptor

This package can be used to intercept attribute param values during serialization/deserialization process.

NOTES

It’s THREAD SAFE.

IMPORTANT

Use this tool when no other option left. Avoid using it, as it drastically hits the performance due to heavy use of reflection behind the scene. Moreover, never use it in combo with Newtonsoft.Json, as the interceptor, in run-time, generates new types for each serialization/deserialization operation and passes those types to the serializer at hand. In case of Newtonsoft.Json, the memory allocated for the dynamically generated types will never get cleaned up, because of Newtonsoft.Json holding the references to those types in his internal cache for faster contract-resolve operations, and thus, the allocated memory will constantly grow. You can use System.Text.Json or any serializer which does not implement any caching, or the caching can be disabled.

LIMITATIONS

  • Fields not supported. Only public non-static props are serialized/deserialized;

  • Root type and types of the props must be public(not declared in any non-public types either) and have a default parameterless constructor;

  • Only param values of attributes attached to types and properties can be intercepted;

  • Not all enumerables supported. Allowed only arrays of any number of dimensions supported by CLR and types from System.Collections.Generic that implement generic ICollection interface;

  • Inheritance supported partially. If you have a prop of type X and assign to that prop a value of type Y and Y is a subclass of X, then only props of type X will be serialized/deserialized, those of type Y which are not in X will be ignored;

USAGE

Let’s look at how we can intercept the serialization attribute param values in run-time. In the example below we’re going to intercept System.Text.Json serialization and deserialization.

First we create our interceptor attribute, inheriting from the abstract class SerializationInterceptor.Attributes.InterceptorAttribute:

public class JsonPropertyNameInterceptorAttribute : SerializationInterceptor.Attributes.InterceptorAttribute
{
    public JsonPropertyNameInterceptorAttribute(string interceptorId)
        : base(interceptorId, typeof(JsonPropertyNameAttribute))
    {
    }

    protected override void Intercept(in SerializationInterceptor.Attributes.AttributeParams originalAttributeParams, object context)
    {
        object value;
        switch (InterceptorId)
        {
            case "some id":
                value = "some value";
                break;
            case "another id":
                value = "another value";
                break;
            default:
                return;
        }
        originalAttributeParams.ConstructorArgs.First().ArgValue = value;
    }
}

Then we place the interceptor attribute on the respective prop near the attribute we want to intercept:

public class Report
{
    [JsonPropertyName("Title")]
    public string Title { get; set; }

    [JsonPropertyNameInterceptor("some id")]
    [JsonPropertyName("some value you want to intercept")]
    public string SomeValue { get; set; }

    [JsonPropertyNameInterceptor("another id")]
    [JsonPropertyName("another value you want to intercept")]
    public string AnotherValue { get; set; }
}

Then we launch the serialization using the static class SerializationInterceptor.Interceptor like this:

var serializedObj = SerializationInterceptor.Interceptor.InterceptSerialization(
    obj,
    objType,
    (o, t) =>
    {
        return JsonSerializer.Serialize(o, t, new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve });
    });

Deserialization is as easy as that:

var deserializedObj = SerializationInterceptor.Interceptor.InterceptDeserialization(
    @string,
    objType,
    (s, t) =>
    {
        return JsonSerializer.Deserialize(s, t, new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve });
    });

Hope this tutorial and package helped you. Good luck! :)