Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Linq;
- using System.Reflection;
- using Newtonsoft.Json;
- using BenchmarkDotNet.Attributes;
- using BenchmarkDotNet.Running;
- using Newtonsoft.Json.Linq;
- using Newtonsoft.Json.Serialization;
- namespace ConsoleApp
- {
- internal class Program
- {
- static void Main()
- {
- BenchmarkRunner.Run<ListBenchmarks>();
- }
- }
- //Attribute used to decorate properties containing sensitive data
- [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
- public class SensitiveDataAttribute : Attribute
- {
- public SensitiveDataAttribute(string mask = "***")
- {
- Mask = mask;
- }
- public string Mask { get; } //Adjustable mask
- }
- public class ClassWithSensitiveData : IContainSecretData
- {
- [JsonIgnore]
- public string Header { get; set; } //This will not be serialized at all
- public string UserName { get; set; }
- [SensitiveData]
- public string Password { get; set; } //This will be serialized in form "Password=***"
- public SubClassWithSensitiveData SensitiveData { get; set; }
- }
- public class SubClassWithSensitiveData : IContainSecretData
- {
- [SensitiveData]
- public string Header { get; set; } //Nested data we want to protect
- public string NotSecret { get; set; }
- }
- public interface IContainSecretData { } //Marker interface to recognize the objects containing sensitive data
- public class MaskSensitiveDataConverter : JsonConverter
- {
- public override bool CanConvert(Type objectType)
- {
- return typeof(IContainSecretData).IsAssignableFrom(objectType);
- }
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- var jObject = new JObject();
- foreach (var property in value.GetType().GetProperties())
- {
- var attributes = property.GetCustomAttributes(true);
- if (attributes.Any(attr => attr is JsonIgnoreAttribute)) { continue; }
- var secretAttribute = attributes.OfType<SensitiveDataAttribute>().FirstOrDefault();
- if (secretAttribute != null)
- {
- jObject.Add(property.Name, secretAttribute.Mask);
- }
- else
- {
- var propValue = property.GetValue(value);
- if (propValue != null || serializer.NullValueHandling == NullValueHandling.Include)
- {
- var propToken = propValue != null ? JToken.FromObject(propValue, serializer) : JValue.CreateNull();
- jObject.Add(property.Name, propToken);
- }
- }
- }
- jObject.WriteTo(writer);
- }
- public override bool CanRead => false;
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException("CanRead is false, this method cannot be invoked.");
- }
- public class MaskSensitiveDataProvider : IValueProvider
- {
- const string _sesitiveDatatag = "***";
- public object GetValue(object target)
- {
- return _sesitiveDatatag;
- }
- public void SetValue(object target, object value)
- {
- target = _sesitiveDatatag;
- }
- }
- public class MaskSensitiveDataResolver : DefaultContractResolver
- {
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
- {
- var property = base.CreateProperty(member, memberSerialization);
- if (member is PropertyInfo)
- {
- var prop = (PropertyInfo)member;
- var isSensitiveData = Attribute.IsDefined(prop, typeof(SensitiveDataAttribute));
- if (isSensitiveData)
- {
- property.ValueProvider = new MaskSensitiveDataProvider();
- }
- }
- return property;
- }
- }
- public class ListBenchmarks
- {
- //Base test to compare results with. It just serializes the data without any modifications
- [Benchmark(Baseline = true)]
- public string WithoutConverter()
- {
- var data = new ClassWithSensitiveData
- {
- Password = "password",
- SensitiveData = new SubClassWithSensitiveData
- {
- Header = "HEADER",
- NotSecret = "NotSecret"
- }
- };
- return JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings
- {
- NullValueHandling = NullValueHandling.Ignore,
- ReferenceLoopHandling = ReferenceLoopHandling.Ignore
- });
- }
- //Test that serializes using converter
- [Benchmark]
- public string WithConverter()
- {
- var data = new ClassWithSensitiveData
- {
- Password = "password",
- SensitiveData = new SubClassWithSensitiveData
- {
- Header = "HEADER",
- NotSecret = "NotSecret"
- }
- };
- return JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings
- {
- NullValueHandling = NullValueHandling.Ignore,
- ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
- Converters = new[] { new MaskSensitiveDataConverter() }
- });
- }
- //And the one that serializes using resolver
- [Benchmark]
- public string WithDataResolver()
- {
- var data = new ClassWithSensitiveData
- {
- Password = "password",
- SensitiveData = new SubClassWithSensitiveData
- {
- Header = "HEADER",
- NotSecret = "NotSecret"
- }
- };
- return JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings
- {
- NullValueHandling = NullValueHandling.Ignore,
- ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
- ContractResolver = new MaskSensitiveDataResolver()
- });
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement