зеркало из https://github.com/akkadotnet/Hyperion.git
Add type filtering feature (#281)
* Add type filtering feature * fix implicit typed variable and lambda expression build error * Add documentation * Deserializer type filter should work on downcasted type * add XML-DOC * Update API Approval list
This commit is contained in:
Родитель
7a781559c9
Коммит
122f5af36d
58
README.md
58
README.md
|
@ -48,6 +48,60 @@ var serializer = new Serializer(options);
|
|||
|
||||
This is essential for frameworks like Akka.NET where we need to be able to resolve live Actor References in the deserializing system.
|
||||
|
||||
## Whitelisting Types On Deserialization
|
||||
|
||||
Sometimes we need to limit the types that are allowed to be deserialized for security reasons. For this reason, you can either pass a class instance that implements the `ITypeFilter` interface into the `SerializerOptions` or use the `TypeFilterBuilder` class to build a `TypeFilter` that Hyperion can use to filter out any possibly harmful injection attack during deserialization.
|
||||
|
||||
using the `ITypeFilter` interface:
|
||||
|
||||
```c#
|
||||
public sealed class TypeFilter : ITypeFilter
|
||||
{
|
||||
public ImmutableHashSet<string> FilteredTypes { get; }
|
||||
|
||||
internal TypeFilter(IEnumerable<Type> types)
|
||||
{
|
||||
FilteredTypes = types.Select(t => t.GetShortAssemblyQualifiedName()).ToImmutableHashSet();
|
||||
}
|
||||
|
||||
public bool IsAllowed(string typeName)
|
||||
=> FilteredTypes.Any(t => t == typeName);
|
||||
}
|
||||
```
|
||||
|
||||
using the `TypeFilterBuilder` convenience builder:
|
||||
|
||||
```c#
|
||||
var typeFilter = TypeFilterBuilder.Create()
|
||||
.Include<AllowedClassA>()
|
||||
.Include<AllowedClassB>()
|
||||
.Build();
|
||||
|
||||
var options = SerializerOptions.Default
|
||||
.WithTypeFilter(typeFilter);
|
||||
|
||||
var serializer = new Serializer(options);
|
||||
```
|
||||
|
||||
### Convert Whitelist To Blacklist
|
||||
|
||||
To do blacklisting instead of whitelisting a list of types, you will need to do a slight modification to the TypeFilter class.
|
||||
|
||||
```c#
|
||||
public sealed class TypeFilter : ITypeFilter
|
||||
{
|
||||
public ImmutableHashSet<string> FilteredTypes { get; }
|
||||
|
||||
internal TypeFilter(IEnumerable<Type> types)
|
||||
{
|
||||
FilteredTypes = types.Select(t => t.GetShortAssemblyQualifiedName()).ToImmutableHashSet();
|
||||
}
|
||||
|
||||
public bool IsAllowed(string typeName)
|
||||
=> FilteredTypes.All(t => t != typeName);
|
||||
}
|
||||
```
|
||||
|
||||
## Version Tolerance
|
||||
|
||||
Hyperion has been designed to work in multiple modes in terms of version tolerance vs. performance.
|
||||
|
@ -55,13 +109,13 @@ Hyperion has been designed to work in multiple modes in terms of version toleran
|
|||
1. Pre Register Types, when using "Pre registered types", Hyperion will only emit a type ID in the output stream.
|
||||
This results in the best performance, but is also fragile if different clients have different versions of the contract types.
|
||||
2. Non Versioned, this is largely the same as the above, but the serializer does not need to know about your types up front. it will embed the fully qualified typename
|
||||
in the outputstream. this results in a larger payload and some performance overhead.
|
||||
in the output stream. this results in a larger payload and some performance overhead.
|
||||
3. Versioned, in this mode, Hyperion will emit both type names and field information in the output stream.
|
||||
This allows systems to have slightly different versions of the contract types where some fields may have been added or removed.
|
||||
|
||||
Hyperion has been designed as a wire format, point to point for soft realtime scenarios.
|
||||
If you need a format that is durable for persistence over time.
|
||||
e.g. EventSourcing or for message queues, then Protobuf or MS Bond is probably a better choise as those formats have been designed for true version tolerance.
|
||||
e.g. EventSourcing or for message queues, then Protobuf or MS Bond is probably a better choice as those formats have been designed for true version tolerance.
|
||||
|
||||
## Performance
|
||||
|
||||
|
|
|
@ -41,6 +41,11 @@ namespace Hyperion
|
|||
public void TrackDeserializedType([Hyperion.Internal.NotNull] System.Type type) { }
|
||||
public void TrackDeserializedTypeWithVersion([Hyperion.Internal.NotNull] System.Type type, [Hyperion.Internal.NotNull] Hyperion.TypeVersionInfo versionInfo) { }
|
||||
}
|
||||
public sealed class DisabledTypeFilter : Hyperion.ITypeFilter
|
||||
{
|
||||
public static readonly Hyperion.DisabledTypeFilter Instance;
|
||||
public bool IsAllowed(string typeName) { }
|
||||
}
|
||||
public delegate object FieldInfoReader(object obj);
|
||||
public delegate void FieldInfoWriter(object obj, object value);
|
||||
public delegate void FieldReader(System.IO.Stream stream, object obj, Hyperion.DeserializerSession session);
|
||||
|
@ -49,6 +54,10 @@ namespace Hyperion
|
|||
{
|
||||
void BuildSerializer(Hyperion.Serializer serializer, Hyperion.ValueSerializers.ObjectSerializer objectSerializer);
|
||||
}
|
||||
public interface ITypeFilter
|
||||
{
|
||||
bool IsAllowed(string typeName);
|
||||
}
|
||||
[System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.All, AllowMultiple=false, Inherited=true)]
|
||||
public sealed class IgnoreAttribute : System.Attribute
|
||||
{
|
||||
|
@ -90,11 +99,16 @@ namespace Hyperion
|
|||
public class SerializerOptions
|
||||
{
|
||||
public static readonly Hyperion.SerializerOptions Default;
|
||||
[System.Obsolete]
|
||||
[System.Obsolete("This constructor is deprecated and will be removed in the future, please use the " +
|
||||
"one with the packageNameOverrides argument")]
|
||||
public SerializerOptions(bool versionTolerance = false, bool preserveObjectReferences = false, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates = null, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories = null, System.Collections.Generic.IEnumerable<System.Type> knownTypes = null, bool ignoreISerializable = false) { }
|
||||
[System.Obsolete]
|
||||
[System.Obsolete("This constructor is deprecated and will be removed in the future, please use the " +
|
||||
"one with the disallowUnsafeTypes argument")]
|
||||
public SerializerOptions(bool versionTolerance, bool preserveObjectReferences, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories, System.Collections.Generic.IEnumerable<System.Type> knownTypes, bool ignoreISerializable, System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides) { }
|
||||
[System.Obsolete("This constructor is deprecated and will be removed in the future, please use the " +
|
||||
"one with the typeFilter argument")]
|
||||
public SerializerOptions(bool versionTolerance, bool preserveObjectReferences, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories, System.Collections.Generic.IEnumerable<System.Type> knownTypes, bool ignoreISerializable, System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides, bool disallowUnsafeTypes) { }
|
||||
public SerializerOptions(bool versionTolerance, bool preserveObjectReferences, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories, System.Collections.Generic.IEnumerable<System.Type> knownTypes, bool ignoreISerializable, System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides, bool disallowUnsafeTypes, Hyperion.ITypeFilter typeFilter) { }
|
||||
public Hyperion.SerializerOptions WithDisallowUnsafeType(bool disallowUnsafeType) { }
|
||||
public Hyperion.SerializerOptions WithIgnoreSerializable(bool ignoreISerializable) { }
|
||||
public Hyperion.SerializerOptions WithKnownTypes(System.Collections.Generic.IEnumerable<System.Type> knownTypes) { }
|
||||
|
@ -102,6 +116,7 @@ namespace Hyperion
|
|||
public Hyperion.SerializerOptions WithPreserveObjectReferences(bool preserveObjectReferences) { }
|
||||
public Hyperion.SerializerOptions WithSerializerFactory(System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories) { }
|
||||
public Hyperion.SerializerOptions WithSurrogates(System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates) { }
|
||||
public Hyperion.SerializerOptions WithTypeFilter(Hyperion.ITypeFilter typeFilter) { }
|
||||
public Hyperion.SerializerOptions WithVersionTolerance(bool versionTolerance) { }
|
||||
}
|
||||
public class SerializerSession
|
||||
|
@ -130,6 +145,18 @@ namespace Hyperion
|
|||
{
|
||||
public Surrogate(System.Func<TSource, TSurrogate> toSurrogate, System.Func<TSurrogate, TSource> fromSurrogate) { }
|
||||
}
|
||||
public sealed class TypeFilter : Hyperion.ITypeFilter
|
||||
{
|
||||
public System.Collections.Immutable.ImmutableHashSet<string> FilteredTypes { get; }
|
||||
public bool IsAllowed(string typeName) { }
|
||||
}
|
||||
public class TypeFilterBuilder
|
||||
{
|
||||
public Hyperion.TypeFilter Build() { }
|
||||
public Hyperion.TypeFilterBuilder Include(System.Type type) { }
|
||||
public Hyperion.TypeFilterBuilder Include<T>() { }
|
||||
public static Hyperion.TypeFilterBuilder Create() { }
|
||||
}
|
||||
public class TypeVersionInfo
|
||||
{
|
||||
public TypeVersionInfo() { }
|
||||
|
@ -591,6 +618,10 @@ namespace Hyperion.Internal
|
|||
public Hyperion.Internal.ImplicitUseTargetFlags TargetFlags { get; }
|
||||
public Hyperion.Internal.ImplicitUseKindFlags UseKindFlags { get; }
|
||||
}
|
||||
public class UserEvilDeserializationException : Hyperion.Internal.EvilDeserializationException
|
||||
{
|
||||
public UserEvilDeserializationException(string message, string typeString) { }
|
||||
}
|
||||
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.All)]
|
||||
public sealed class ValueProviderAttribute : System.Attribute
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Hyperion.Extensions;
|
||||
using Hyperion.Internal;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Hyperion.Tests
|
||||
{
|
||||
|
@ -22,5 +24,64 @@ namespace Hyperion.Tests
|
|||
serializer.Deserialize<DirectoryInfo>(stream));
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassA
|
||||
{ }
|
||||
|
||||
internal class ClassB
|
||||
{ }
|
||||
|
||||
internal class ClassC
|
||||
{ }
|
||||
|
||||
[Fact]
|
||||
public void TypeFilterShouldThrowOnNaughtyType()
|
||||
{
|
||||
var typeFilter = TypeFilterBuilder.Create()
|
||||
.Include<ClassA>()
|
||||
.Include<ClassB>()
|
||||
.Build();
|
||||
|
||||
var options = SerializerOptions.Default
|
||||
.WithTypeFilter(typeFilter);
|
||||
|
||||
var serializer = new Serializer(options);
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
serializer.Serialize(new ClassA(), stream);
|
||||
stream.Position = 0;
|
||||
Action act = () => serializer.Deserialize<ClassA>(stream);
|
||||
act.Should().NotThrow();
|
||||
|
||||
stream.Position = 0;
|
||||
Action actObj = () => serializer.Deserialize<object>(stream);
|
||||
actObj.Should().NotThrow();
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
serializer.Serialize(new ClassB(), stream);
|
||||
stream.Position = 0;
|
||||
Action act = () => serializer.Deserialize<ClassB>(stream);
|
||||
act.Should().NotThrow();
|
||||
|
||||
stream.Position = 0;
|
||||
Action actObj = () => serializer.Deserialize<object>(stream);
|
||||
actObj.Should().NotThrow();
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
serializer.Serialize(new ClassC(), stream);
|
||||
stream.Position = 0;
|
||||
Action act = () => serializer.Deserialize<ClassC>(stream);
|
||||
act.Should().Throw<UserEvilDeserializationException>();
|
||||
|
||||
stream.Position = 0;
|
||||
Action actObj = () => serializer.Deserialize<object>(stream);
|
||||
actObj.Should().Throw<UserEvilDeserializationException>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -162,7 +162,8 @@ namespace Hyperion.Extensions
|
|||
break;
|
||||
}
|
||||
|
||||
return LoadTypeByName(shortName, session.Serializer.Options.DisallowUnsafeTypes);
|
||||
var options = session.Serializer.Options;
|
||||
return LoadTypeByName(shortName, options.DisallowUnsafeTypes, options.TypeFilter);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -192,12 +193,14 @@ namespace Hyperion.Extensions
|
|||
return false;
|
||||
}
|
||||
|
||||
public static Type LoadTypeByName(string name, bool disallowUnsafeTypes)
|
||||
public static Type LoadTypeByName(string name, bool disallowUnsafeTypes, ITypeFilter typeFilter)
|
||||
{
|
||||
if (disallowUnsafeTypes && UnsafeTypesDenySet.Any(name.Contains))
|
||||
if (disallowUnsafeTypes)
|
||||
{
|
||||
throw new EvilDeserializationException(
|
||||
"Unsafe Type Deserialization Detected!", name);
|
||||
if(UnsafeTypesDenySet.Any(name.Contains))
|
||||
throw new EvilDeserializationException("Unsafe Type Deserialization Detected!", name);
|
||||
if(!typeFilter.IsAllowed(name))
|
||||
throw new UserEvilDeserializationException("Unsafe Type Deserialization Detected!", name);
|
||||
}
|
||||
try
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
namespace Hyperion
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a callback to allow a user defined Type filter during certain operations
|
||||
/// </summary>
|
||||
public interface ITypeFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if a fully qualified class name is allowed to be processed or not
|
||||
/// </summary>
|
||||
/// <param name="typeName">The fully qualified class name of the type to be filtered</param>
|
||||
/// <returns><c>true</c> if a type is allowed</returns>
|
||||
bool IsAllowed(string typeName);
|
||||
}
|
||||
}
|
|
@ -30,6 +30,13 @@ namespace Hyperion.Internal
|
|||
|
||||
public string BadTypeString { get; }
|
||||
}
|
||||
|
||||
public class UserEvilDeserializationException : EvilDeserializationException
|
||||
{
|
||||
public UserEvilDeserializationException(string message, string typeString) : base(message, typeString)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the value of the marked element could be <c>null</c> sometimes,
|
||||
/// so the check for <c>null</c> is necessary before its usage.
|
||||
|
|
|
@ -16,15 +16,7 @@ namespace Hyperion
|
|||
{
|
||||
public class SerializerOptions
|
||||
{
|
||||
public static readonly SerializerOptions Default = new SerializerOptions(
|
||||
versionTolerance: false,
|
||||
preserveObjectReferences: false,
|
||||
surrogates: null,
|
||||
serializerFactories: null,
|
||||
knownTypes: null,
|
||||
ignoreISerializable: false,
|
||||
packageNameOverrides: null,
|
||||
disallowUnsafeTypes: true);
|
||||
public static readonly SerializerOptions Default = new SerializerOptions();
|
||||
|
||||
internal static List<Func<string, string>> DefaultPackageNameOverrides()
|
||||
{
|
||||
|
@ -81,8 +73,9 @@ namespace Hyperion
|
|||
internal readonly Dictionary<Type, ushort> KnownTypesDict = new Dictionary<Type, ushort>();
|
||||
internal readonly List<Func<string, string>> CrossFrameworkPackageNameOverrides = DefaultPackageNameOverrides();
|
||||
internal readonly bool DisallowUnsafeTypes;
|
||||
|
||||
[Obsolete]
|
||||
internal readonly ITypeFilter TypeFilter;
|
||||
|
||||
[Obsolete(message:"This constructor is deprecated and will be removed in the future, please use the one with the packageNameOverrides argument")]
|
||||
public SerializerOptions(
|
||||
bool versionTolerance = false,
|
||||
bool preserveObjectReferences = false,
|
||||
|
@ -93,7 +86,7 @@ namespace Hyperion
|
|||
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, null)
|
||||
{ }
|
||||
|
||||
[Obsolete]
|
||||
[Obsolete(message:"This constructor is deprecated and will be removed in the future, please use the one with the disallowUnsafeTypes argument")]
|
||||
public SerializerOptions(
|
||||
bool versionTolerance,
|
||||
bool preserveObjectReferences,
|
||||
|
@ -102,7 +95,20 @@ namespace Hyperion
|
|||
IEnumerable<Type> knownTypes,
|
||||
bool ignoreISerializable,
|
||||
IEnumerable<Func<string, string>> packageNameOverrides)
|
||||
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, null, true)
|
||||
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, packageNameOverrides, true)
|
||||
{ }
|
||||
|
||||
[Obsolete(message:"This constructor is deprecated and will be removed in the future, please use the one with the typeFilter argument")]
|
||||
public SerializerOptions(
|
||||
bool versionTolerance,
|
||||
bool preserveObjectReferences,
|
||||
IEnumerable<Surrogate> surrogates,
|
||||
IEnumerable<ValueSerializerFactory> serializerFactories,
|
||||
IEnumerable<Type> knownTypes,
|
||||
bool ignoreISerializable,
|
||||
IEnumerable<Func<string, string>> packageNameOverrides,
|
||||
bool disallowUnsafeTypes)
|
||||
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, packageNameOverrides, disallowUnsafeTypes, DisabledTypeFilter.Instance)
|
||||
{ }
|
||||
|
||||
public SerializerOptions(
|
||||
|
@ -113,7 +119,8 @@ namespace Hyperion
|
|||
IEnumerable<Type> knownTypes,
|
||||
bool ignoreISerializable,
|
||||
IEnumerable<Func<string, string>> packageNameOverrides,
|
||||
bool disallowUnsafeTypes)
|
||||
bool disallowUnsafeTypes,
|
||||
ITypeFilter typeFilter)
|
||||
{
|
||||
VersionTolerance = versionTolerance;
|
||||
Surrogates = surrogates?.ToArray() ?? EmptySurrogates;
|
||||
|
@ -136,6 +143,7 @@ namespace Hyperion
|
|||
CrossFrameworkPackageNameOverrides.AddRange(packageNameOverrides);
|
||||
|
||||
DisallowUnsafeTypes = disallowUnsafeTypes;
|
||||
TypeFilter = typeFilter ?? DisabledTypeFilter.Instance;
|
||||
}
|
||||
|
||||
public SerializerOptions WithVersionTolerance(bool versionTolerance)
|
||||
|
@ -154,6 +162,8 @@ namespace Hyperion
|
|||
=> Copy(packageNameOverrides: packageNameOverrides);
|
||||
public SerializerOptions WithDisallowUnsafeType(bool disallowUnsafeType)
|
||||
=> Copy(disallowUnsafeType: disallowUnsafeType);
|
||||
public SerializerOptions WithTypeFilter(ITypeFilter typeFilter)
|
||||
=> Copy(typeFilter: typeFilter);
|
||||
|
||||
private SerializerOptions Copy(
|
||||
bool? versionTolerance = null,
|
||||
|
@ -163,7 +173,8 @@ namespace Hyperion
|
|||
IEnumerable<Type> knownTypes = null,
|
||||
bool? ignoreISerializable = null,
|
||||
IEnumerable<Func<string, string>> packageNameOverrides = null,
|
||||
bool? disallowUnsafeType = null)
|
||||
bool? disallowUnsafeType = null,
|
||||
ITypeFilter typeFilter = null)
|
||||
=> new SerializerOptions(
|
||||
versionTolerance ?? VersionTolerance,
|
||||
preserveObjectReferences ?? PreserveObjectReferences,
|
||||
|
@ -172,7 +183,8 @@ namespace Hyperion
|
|||
knownTypes ?? KnownTypes,
|
||||
ignoreISerializable ?? IgnoreISerializable,
|
||||
packageNameOverrides ?? CrossFrameworkPackageNameOverrides,
|
||||
disallowUnsafeType ?? DisallowUnsafeTypes
|
||||
disallowUnsafeType ?? DisallowUnsafeTypes,
|
||||
typeFilter ?? TypeFilter
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Hyperion.Extensions;
|
||||
|
||||
namespace Hyperion
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public sealed class TypeFilter : ITypeFilter
|
||||
{
|
||||
public ImmutableHashSet<string> FilteredTypes { get; }
|
||||
|
||||
internal TypeFilter(IEnumerable<Type> types)
|
||||
{
|
||||
FilteredTypes = types.Select(t => t.GetShortAssemblyQualifiedName()).ToImmutableHashSet();
|
||||
}
|
||||
|
||||
public bool IsAllowed(string typeName)
|
||||
=> FilteredTypes.Any(t => t == typeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A disabled type filter that always returns true
|
||||
/// </summary>
|
||||
public sealed class DisabledTypeFilter : ITypeFilter
|
||||
{
|
||||
public static readonly DisabledTypeFilter Instance = new DisabledTypeFilter();
|
||||
|
||||
private DisabledTypeFilter() { }
|
||||
|
||||
public bool IsAllowed(string typeName) => true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Hyperion
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to programatically create a <see cref="TypeFilter"/> using fluent builder pattern.
|
||||
/// </summary>
|
||||
public class TypeFilterBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="TypeFilterBuilder"/>
|
||||
/// </summary>
|
||||
/// <returns>a new instance of <see cref="TypeFilterBuilder"/> </returns>
|
||||
public static TypeFilterBuilder Create() => new TypeFilterBuilder();
|
||||
|
||||
private readonly List<Type> _types = new List<Type>();
|
||||
|
||||
private TypeFilterBuilder()
|
||||
{ }
|
||||
|
||||
public TypeFilterBuilder Include<T>()
|
||||
{
|
||||
return Include(typeof(T));
|
||||
}
|
||||
|
||||
public TypeFilterBuilder Include(Type type)
|
||||
{
|
||||
_types.Add(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TypeFilter Build()
|
||||
=> new TypeFilter(_types);
|
||||
}
|
||||
}
|
|
@ -69,8 +69,9 @@ namespace Hyperion.ValueSerializers
|
|||
if (shortname == null)
|
||||
return null;
|
||||
|
||||
var options = session.Serializer.Options;
|
||||
var type = TypeNameLookup.GetOrAdd(shortname,
|
||||
name => TypeEx.LoadTypeByName(shortname, session.Serializer.Options.DisallowUnsafeTypes));
|
||||
name => TypeEx.LoadTypeByName(shortname, options.DisallowUnsafeTypes, options.TypeFilter));
|
||||
|
||||
//add the deserialized type to lookup
|
||||
if (session.Serializer.Options.PreserveObjectReferences)
|
||||
|
|
Загрузка…
Ссылка в новой задаче