我正在使用SharpSerializer來序列化/反序列化物件。
我希望能夠在反序列化時忽略特定屬性。
SharpSerializer 可以選擇按屬性或按類和屬性名稱忽略屬性:
SharpSerializerSettings.AdvancedSettings.AttributesToIgnore
SharpSerializerSettings.AdvancedSettings.PropertiesToIgnore
但似乎這些設定僅用于從序列化中忽略,而不是從反序列化中忽略(我使用 GitHub 源代碼和 NugetPackage 進行了測驗)。
我對么?
有沒有辦法忽略反序列化的屬性/屬性?
聚苯乙烯
- 我確信還有其他很棒的序列化庫,但是更改代碼和所有現有的序列化檔案需要付出很大的努力。
- 我在 GitHub 專案上打開了一個問題,但該專案自 2018 年以來似乎不再活躍。
- 具有要忽略的屬性的物件不必是根物件。
uj5u.com熱心網友回復:
您是正確的,SharpSerializer在反序列化時沒有實作忽略屬性值。這可以從參考來源驗證ObjectFactory.fillProperties(object obj, IEnumerable<Property> properties):
private void fillProperties(object obj, IEnumerable<Property> properties) { foreach (Property property in properties) { PropertyInfo propertyInfo = obj.GetType().GetProperty(property.Name); if (propertyInfo == null) continue; object value = CreateObject(property); if (value == null) continue; propertyInfo.SetValue(obj, value, _emptyObjectArray); } }
此代碼使用反射無條件地將從序列化流讀取的任何屬性設定到傳入物件中,而不檢查被忽略的屬性或屬性的串列。
因此,忽略所需屬性的唯一方法似乎是創建自己的版本XmlPropertyDeserializer或BinaryPropertyDeserializer跳過或過濾不需要的屬性。以下是 XML 的一種可能實作。此實作Property像往常一樣將屬性從 XML 讀取到層次結構中,然后應用過濾器操作來移除與應用了自定義屬性的 .NET 屬性對應的屬性[SharpSerializerIgnoreForDeserialize],最后使用修剪過的.NET 屬性創建物件樹Property。
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class SharpSerializerIgnoreForDeserializeAttribute : System.Attribute { }
public class PropertyDeserializerDecorator : IPropertyDeserializer
{
readonly IPropertyDeserializer deserializer;
public PropertyDeserializerDecorator(IPropertyDeserializer deserializer) => this.deserializer = deserializer ?? throw new ArgumentNullException();
public virtual void Open(Stream stream) => deserializer.Open(stream);
public virtual Property Deserialize() => deserializer.Deserialize();
public virtual void Close() => deserializer.Close();
}
public class CustomPropertyDeserializer : PropertyDeserializerDecorator
{
Action<Property> deserializePropertyAction;
public CustomPropertyDeserializer(IPropertyDeserializer deserializer, Action<Property> deserializePropertyAction = default) : base(deserializer) => this.deserializePropertyAction = deserializePropertyAction;
public override Property Deserialize()
{
var property = base.Deserialize();
if (deserializePropertyAction != null)
property.WalkProperties(p => deserializePropertyAction(p));
return property;
}
}
public static partial class SharpSerializerExtensions
{
public static SharpSerializer Create(SharpSerializerXmlSettings settings, Action<Property> deserializePropertyAction = default)
{
// Adapted from https://github.com/polenter/SharpSerializer/blob/42f9a20b3934a7f2cece356cc8116a861cec0b91/SharpSerializer/SharpSerializer.cs#L139
// By https://github.com/polenter
var typeNameConverter = settings.AdvancedSettings.TypeNameConverter ??
new TypeNameConverter(
settings.IncludeAssemblyVersionInTypeName,
settings.IncludeCultureInTypeName,
settings.IncludePublicKeyTokenInTypeName);
// SimpleValueConverter
var simpleValueConverter = settings.AdvancedSettings.SimpleValueConverter ?? new SimpleValueConverter(settings.Culture, typeNameConverter);
// XmlWriterSettings
var xmlWriterSettings = new XmlWriterSettings
{
Encoding = settings.Encoding,
Indent = true,
OmitXmlDeclaration = true,
};
// XmlReaderSettings
var xmlReaderSettings = new XmlReaderSettings
{
IgnoreComments = true,
IgnoreWhitespace = true,
};
// Create Serializer and Deserializer
var reader = new DefaultXmlReader(typeNameConverter, simpleValueConverter, xmlReaderSettings);
var writer = new DefaultXmlWriter(typeNameConverter, simpleValueConverter, xmlWriterSettings);
var _serializer = new XmlPropertySerializer(writer);
var _deserializer = new CustomPropertyDeserializer(new XmlPropertyDeserializer(reader), deserializePropertyAction);
var serializer = new SharpSerializer(_serializer, _deserializer)
{
//InstanceCreator = settings.InstanceCreator ?? new DefaultInstanceCreator(), -- InstanceCreator not present in SharpSerializer 3.0.1
RootName = settings.AdvancedSettings.RootName,
};
serializer.PropertyProvider.PropertiesToIgnore = settings.AdvancedSettings.PropertiesToIgnore;
serializer.PropertyProvider.AttributesToIgnore = settings.AdvancedSettings.AttributesToIgnore;
return serializer;
}
public static void WalkProperties(this Property property, Action<Property> action)
{
if (action == null || property == null)
throw new ArgumentNullException();
action(property);
switch (property.Art)
{
case PropertyArt.Collection:
{
foreach (var item in ((CollectionProperty)property).Items)
item.WalkProperties(action);
}
break;
case PropertyArt.Complex:
{
foreach (var item in ((ComplexProperty)property).Properties)
item.WalkProperties(action);
}
break;
case PropertyArt.Dictionary:
{
foreach (var item in ((DictionaryProperty)property).Items)
{
item.Key.WalkProperties(action);
item.Value.WalkProperties(action);
}
}
break;
case PropertyArt.MultiDimensionalArray:
{
foreach (var item in ((MultiDimensionalArrayProperty )property).Items)
item.Value.WalkProperties(action);
}
break;
case PropertyArt.Null:
case PropertyArt.Simple:
case PropertyArt.Reference:
break;
case PropertyArt.SingleDimensionalArray:
{
foreach (var item in ((SingleDimensionalArrayProperty)property).Items)
item.WalkProperties(action);
}
break;
default:
throw new NotImplementedException(property.Art.ToString());
}
}
public static void RemoveIgnoredChildProperties(Property p)
{
if (p.Art == PropertyArt.Complex)
{
var items = ((ComplexProperty)p).Properties;
for (int i = items.Count - 1; i >= 0; i--)
{
if (p.Type.GetProperty(items[i].Name)?.IsDefined(typeof(SharpSerializerIgnoreForDeserializeAttribute), true) == true)
{
items.RemoveAt(i);
}
}
}
}
}
然后,給定以下模型:
public class Root
{
public List<Model> Models { get; set; } = new ();
}
public class Model
{
public string Value { get; set; }
[SharpSerializerIgnoreForDeserialize]
public string IgnoreMe { get; set; }
}
您將使用自定義反序列化XmlPropertyDeserializer如下:
var settings = new SharpSerializerXmlSettings();
var customSerialzier = SharpSerializerExtensions.Create(settings, SharpSerializerExtensions.RemoveIgnoredChildProperties);
var deserialized = (Root)customSerialzier.Deserialize(stream);
如果您需要二進制反序列化,請使用以下工廠方法來創建序列化程式:
public static partial class SharpSerializerExtensions
{
public static SharpSerializer Create(SharpSerializerBinarySettings settings, Action<Property> deserializePropertyAction = default)
{
// Adapted from https://github.com/polenter/SharpSerializer/blob/42f9a20b3934a7f2cece356cc8116a861cec0b91/SharpSerializer/SharpSerializer.cs#L168
// By https://github.com/polenter
var typeNameConverter = settings.AdvancedSettings.TypeNameConverter ??
new TypeNameConverter(
settings.IncludeAssemblyVersionInTypeName,
settings.IncludeCultureInTypeName,
settings.IncludePublicKeyTokenInTypeName);
// Create Serializer and Deserializer
Polenter.Serialization.Advanced.Binary.IBinaryReader reader;
Polenter.Serialization.Advanced.Binary.IBinaryWriter writer;
if (settings.Mode == BinarySerializationMode.Burst)
{
// Burst mode
writer = new BurstBinaryWriter(typeNameConverter, settings.Encoding);
reader = new BurstBinaryReader(typeNameConverter, settings.Encoding);
}
else
{
// Size optimized mode
writer = new SizeOptimizedBinaryWriter(typeNameConverter, settings.Encoding);
reader = new SizeOptimizedBinaryReader(typeNameConverter, settings.Encoding);
}
var _serializer = new BinaryPropertySerializer(writer);
var _deserializer = new CustomPropertyDeserializer(new BinaryPropertyDeserializer(reader), deserializePropertyAction);
var serializer = new SharpSerializer(_serializer, _deserializer)
{
//InstanceCreator = settings.InstanceCreator ?? new DefaultInstanceCreator(), -- InstanceCreator not present in SharpSerializer 3.0.1
RootName = settings.AdvancedSettings.RootName,
};
serializer.PropertyProvider.PropertiesToIgnore = settings.AdvancedSettings.PropertiesToIgnore;
serializer.PropertyProvider.AttributesToIgnore = settings.AdvancedSettings.AttributesToIgnore;
return serializer;
}
}
并做:
var settings = new SharpSerializerBinarySettings();
var customSerialzier = SharpSerializerExtensions.Create(settings, SharpSerializerExtensions.RemoveIgnoredChildProperties);
var deserialized = (Root)customSerialzier.Deserialize(stream);
筆記:
該方法
SharpSerializerExtensions.Create()為藍本SharpSerializer.initialize(SharpSerializerXmlSettings settings),并SharpSerializer.initialize(SharpSerializerBinarySettings settings)通過帕維爾睡姿The version of
SharpSerializeravailable on nuget, version 3.0.1, only includes commits through 10/8/2017. Submissions since then that add the ability to use Autofac as the instance creator are not available via nuget. My code is based on the version available via nuget, and thus does not initializeSharpSerializer.InstanceCreatorwhich was added in 2018. The project appears not to have updated at all since then.SharpSerializer.Deserialize()deserializes to the type specified in the serialization stream rather than to a type specified by the caller. It thus appears vulnerable to the sort of type injection attacks described in Alvaro Mu?oz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf.For details see e.g. TypeNameHandling caution in Newtonsoft Json.
If you are willing to fork, modify and build
SharpSerializeryourself, you might consider updatingObjectFactory.fillProperties(object obj, IEnumerable<Property> properties)to not set ignored properties.
Demo fiddle #1 here for XML, and #2 here for binary.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/353701.html
