public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!CanHandle(context)) { throw new InvalidOperationException($"Cannot handle Type: {context.TargetType.Name} with a {this.GetType().FullName}."); } if (!context.BuiltContextKey.HasValue) { throw new InvalidOperationException($"Failed to build a {nameof(ContextualSerializerLookupKey)} for the Type: {context.TargetType} with Context: {context.ToString()}."); } ITypeSerializerStrategy <TType> serializer = TryCreateSerializer <TType>(context); if (serializer == null) { throw new InvalidOperationException($"Failed to generate a serializer for Type: {context.TargetType.Name} with decorator factory {this.GetType().FullName}."); } return(serializer); }
/// <inheritdoc /> public override bool CanHandle(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context), $"Provided argument {nameof(context)} was null."); } return(context.TargetType.IsArray); }
public static bool HasContextualKey([NotNull] this ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(context.BuiltContextKey.HasValue); }
/// <inheritdoc /> public override bool CanHandle(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //We can handle any type technically return(true); }
/// <inheritdoc /> public override bool CanHandle(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //We can handle strings. Maybe char[] but that's an odd case. return(context.TargetType == typeof(string)); }
public static bool HasMemberAttribute <TAttributeType>([NotNull] this ISerializableTypeContext context) where TAttributeType : Attribute { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(context.MemberMetadata.Any(x => x.GetType() == typeof(TAttributeType))); }
public static ISerializableTypeContext Override([NotNull] this ISerializableTypeContext context, ContextualSerializerLookupKey key) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //Deocrate the context to set the provided key return(new ContextKeyOverrideDecorator(context, key)); }
public ContextKeyOverrideDecorator([NotNull] ISerializableTypeContext context, ContextualSerializerLookupKey key) { if (context == null) { throw new ArgumentNullException(nameof(context)); } managedContext = context; BuiltContextKey = key; }
public static ISerializableTypeContext Override([NotNull] this ISerializableTypeContext context, [NotNull] Type targetType) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } //Decorate the context to override the target type return(new ContextTargetOverrideDecorator(context, targetType)); }
public ContextTargetOverrideDecorator([NotNull] ISerializableTypeContext context, [NotNull] Type targetType) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } managedContext = context; TargetType = targetType; }
/// <inheritdoc /> public override bool CanHandle(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context), $"Provided argument {nameof(context)} was null."); } //Check if the type has wirebase type attributes. //If it does then the type is complex and can have subtypes coming across the wire //Include checking for runtime link information return((context.TargetType.GetTypeInfo().GetCustomAttributes <WireDataContractAttribute>(false).Any() && context.TargetType.GetTypeInfo().GetCustomAttribute <WireDataContractAttribute>(false).ExpectRuntimeLink) || context.TargetType.GetTypeInfo().GetCustomAttributes <WireDataContractBaseTypeAttribute>(false).Any() || context.TargetType.GetTypeInfo().GetCustomAttribute <WireDataContractBaseTypeByFlagsAttribute>(false) != null); }
public static bool HasContextualTypeMetadata([NotNull] this ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //If there is no context requirement then there is probably no context metadata or shouldn't be if (context.ContextRequirement != SerializationContextRequirement.RequiresContext) { return(false); } return(context.TypeMetadata.Any()); }
/// <summary> /// Attempts to produce a decorated serializer for the provided <see cref="ISerializableTypeContext"/>. /// </summary> /// <param name="context">The context.</param> /// <exception cref="InvalidOperationException">Throws if the <see cref="ITypeSerializerStrategy{TType}"/> could not be created.</exception> /// <returns>A decorated serializer.</returns> public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //Build the contextual key first. We used to do this as one of the last steps but we need //to grab the key to check if it already exists. context.BuiltContextKey = lookupKeyFactoryService.Create(context); if (serializerProviderService.HasSerializerFor(context.BuiltContextKey.Value)) { throw new InvalidOperationException($"Tried to create multiple serializer for already created serialize with Context: {context.ToString()}."); } //This may look weird but this was done for perf reasons //We can't be passing around IEnumerables and ToListing them //Otherwise complex types will take seconds to register List <ISerializableTypeContext> contexts = new List <ISerializableTypeContext>(200); GetAllSubTypeContexts(context, contexts); IEnumerable <ISerializableTypeContext> byLikelyRegisteration = contexts .Distinct(new SerializableTypeContextComparer()) .ToList(); //We must register all subcontexts first foreach (ISerializableTypeContext subContext in byLikelyRegisteration) { MethodInfo info = null; if (CachedGenericInternalCreateMap.ContainsKey(subContext.TargetType)) { info = CachedGenericInternalCreateMap[subContext.TargetType]; } else { info = (CachedGenericInternalCreateMap[subContext.TargetType] = GetType().GetTypeInfo().GetMethod(nameof(InternalCreate), BindingFlags.NonPublic | BindingFlags.Instance) .MakeGenericMethod(subContext.TargetType)); } info.Invoke(this, new object[] { subContext }); } //Now that all dependencies in the object graph are registered we can create the requested type return(InternalCreate <TType>(context)); }
public static TAttributeType GetMemberAttribute <TAttributeType>([NotNull] this ISerializableTypeContext context) where TAttributeType : Attribute { if (context == null) { throw new ArgumentNullException(nameof(context)); } TAttributeType attri = context.MemberMetadata.FirstOrDefault(x => x.GetType() == typeof(TAttributeType)) as TAttributeType; if (attri == null) { throw new InvalidOperationException($"Requested Attribute Type {typeof(TAttributeType).FullName} was unavailable."); } return(attri); }
public static ISerializableTypeContext Override([NotNull] this ISerializableTypeContext context, SerializationContextRequirement requirement) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!Enum.IsDefined(typeof(SerializationContextRequirement), requirement)) { throw new ArgumentOutOfRangeException(nameof(requirement), "Value should be defined in the SerializationContextRequirement enum."); } /*if (!Enum.IsDefined(typeof(SerializationContextRequirement), requirement)) * throw new InvalidEnumArgumentException(nameof(requirement), (int) requirement, * typeof(SerializationContextRequirement));*/ //Deocrate the context to set the provided key return(new ContextRequirementOverrideDecorator(context, requirement)); }
public ContextRequirementOverrideDecorator([NotNull] ISerializableTypeContext context, SerializationContextRequirement requirement) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!Enum.IsDefined(typeof(SerializationContextRequirement), requirement)) { throw new ArgumentOutOfRangeException(nameof(requirement), "Value should be defined in the SerializationContextRequirement enum."); } /*if (!Enum.IsDefined(typeof(SerializationContextRequirement), requirement)) * throw new InvalidEnumArgumentException(nameof(requirement), (int) requirement, * typeof(SerializationContextRequirement));*/ managedContext = context; ContextRequirement = requirement; }
private void RegisterNewSerializerStrategy(ISerializableTypeContext context, ITypeSerializerStrategy strategy) { if (strategy.ContextRequirement == SerializationContextRequirement.Contextless) { StrategyRegistry.RegisterType(context.TargetType, strategy); } else { //TODO: Clean this up if (context.HasContextualKey()) { //Register the serializer with the context key that was built into the serialization context. StrategyRegistry.RegisterType(context.BuiltContextKey.Value.ContextFlags, context.BuiltContextKey.Value.ContextSpecificKey, context.TargetType, strategy); } else { throw new InvalidOperationException($"Serializer was created but Type: {context.TargetType} came with no contextual key in the end for a contextful serialization context."); } } }
//Called as the fallback factory. /// <inheritdoc /> public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //This service acts a the default/fallback factory for serializer creation. If any factory encounters a type //inside of a type that it doesn't know about or requires handling outside of its scope it'll broadcast that //and we will implement more complex handling here ITypeSerializerStrategy <TType> strategy = serializerStrategyFactoryService.Create <TType>(context); //The serializer could be null; we should verify it if (strategy == null) { throw new InvalidOperationException($"Failed to create serializer for Type: {context.TargetType} with Context: {context.ToString()}."); } return(strategy); }
private ITypeSerializerStrategy <TType> InternalCreate <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //TODO: Refactor this. It's duplicated code //We should check if the specified a custom type serializer if (typeof(TType).GetTypeInfo().HasAttribute <IncludeCustomTypeSerializerAttribute>()) { IncludeCustomTypeSerializerAttribute attri = typeof(TType).GetTypeInfo().GetCustomAttribute <IncludeCustomTypeSerializerAttribute>(); if (!typeof(ITypeSerializerStrategy <TType>).GetTypeInfo().IsAssignableFrom(attri.TypeSerializerType)) { throw new InvalidOperationException($"Specified custom Type Serializer Type: {attri.TypeSerializerType} but did not implement {nameof(ITypeSerializerStrategy<TType>)}. Must implment that interface for custom serializers."); } ITypeSerializerStrategy <TType> serializer = Activator.CreateInstance(attri.TypeSerializerType) as ITypeSerializerStrategy <TType>; this.StrategyRegistry.RegisterType(typeof(TType), serializer); return(serializer); } DecoratorHandler handler = decoratorHandlers.First(h => h.CanHandle(context)); ITypeSerializerStrategy <TType> strategy = handler.Create <TType>(context); if (strategy == null) { throw new InvalidOperationException($"Couldn't generate a strategy for Type: {context.TargetType} with Context: {context.BuiltContextKey?.ToString()}."); } //If the serializer is contextless we can register it with the general provider RegisterNewSerializerStrategy(context, strategy); return(strategy); }
private void GetAllSubTypeContexts([NotNull] ISerializableTypeContext context, List <ISerializableTypeContext> knownContexts) { List <ISerializableTypeContext> contexts = GetUnknownUnregisteredSubTypeContexts(context, knownContexts); foreach (ISerializableTypeContext s in contexts) { s.BuiltContextKey = lookupKeyFactoryService.Create(s); } //Get only the new contexts contexts = contexts.Except(knownContexts, new SerializableTypeContextComparer()) .ToList(); //After we've made context unique ones we haven't registered we NEED to make sure that the ones we know in this stack //are included in the knowns we pass to ones below this recurring stack knownContexts.AddRange(contexts); //If there are any new we need to recurr to get their dependencies foreach (var s in contexts) { //We don't return lists anymore. Just add elements instead to avoid allocations GetAllSubTypeContexts(s, knownContexts); } }
/// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ITypeSerializerStrategy <TType> complexTypeSerializerDecorator = new ComplexTypeSerializerDecorator <TType>(new MemberSerializationMediatorCollection <TType>(SerializationMediatorFactory), new LambdabasedDeserializationPrototyeFactory <TType>(), serializerProviderService); //Check for compression flags if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.Compressed)) { complexTypeSerializerDecorator = new CompressionTypeSerializerStrategyDecorator <TType>(complexTypeSerializerDecorator, serializerProviderService.Get <uint>()); } return(complexTypeSerializerDecorator); }
/// <inheritdoc /> public override bool CanHandle(ISerializableTypeContext context) { //Right now we can handle only DateTimes as special complex types. return(context.TargetType == typeof(DateTime) || context.TargetType == typeof(BitArray)); }
private List <ISerializableTypeContext> GetUnknownUnregisteredSubTypeContexts([NotNull] ISerializableTypeContext context, IEnumerable <ISerializableTypeContext> knownContexts) { return(decoratorHandlers.First(h => h.CanHandle(context)) .GetAssociatedSerializationContexts(context) .Select(s => { s.BuiltContextKey = lookupKeyFactoryService.Create(s); return s; }) .Where(s => !serializerProviderService.HasSerializerFor(s.BuiltContextKey.Value)) //make sure we ignore known registered types .Except(knownContexts, new SerializableTypeContextComparer()) .ToList()); }
//TODO: Refactor; mess; too long /// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!context.BuiltContextKey.HasValue) { throw new InvalidOperationException($"Provided {nameof(ISerializableTypeContext)} did not contain a valid {nameof(context.BuiltContextKey)} for Context: {context.ToString()}."); } ICollectionSizeStrategy collectionSizeStrategy = null; //TODO: Handle contextless requests. The future may require a single array serializer for all unknown sizes. if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize)) { int knownSize = context.BuiltContextKey.Value.ContextSpecificKey.Key; collectionSizeStrategy = new FixedSizeCollectionSizeStrategy(knownSize); } else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.SendSize)) { sbyte addedSize = (sbyte)(context.BuiltContextKey.Value.ContextSpecificKey.Key >> 4); //TODO: Is there a way to obsecure this bit fiddling? switch ((SendSizeAttribute.SizeType)(context.BuiltContextKey.Value.ContextSpecificKey.Key & 0b0000_0000_0000_1111)) //get just the key {
/// <inheritdoc /> protected override IEnumerable <ISerializableTypeContext> TryGetAssociatedSerializableContexts(ISerializableTypeContext context) { //We don't need any special types registered return(Enumerable.Empty <ISerializableTypeContext>()); }
//TODO: Refactor /// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (typeof(TType) != typeof(string)) { throw new InvalidOperationException($"{nameof(StringSerializerDecoratorHandler)} cannot handle creation of serializer decorators involves {typeof(string).FullName}."); } if (!context.HasContextualKey()) { throw new ArgumentException($"Provided context {nameof(context)} did not contain a valid {nameof(context.BuiltContextKey)}."); } if (context.ContextRequirement == SerializationContextRequirement.Contextless) { return((ITypeSerializerStrategy <TType>)serializerProviderService.Get <string>()); //The caller should know what he's doing. } //TODO: Throw on invalid metadata combinations ITypeSerializerStrategy <string> serializer = null; Encoding encoding = Encoding.ASCII; if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.Encoding)) { if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.ASCII)) { encoding = Encoding.ASCII; serializer = new StringSerializerStrategy(Encoding.ASCII, SerializationContextRequirement.RequiresContext); } else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF16)) { encoding = Encoding.Unicode; serializer = new StringSerializerStrategy(Encoding.Unicode, SerializationContextRequirement.RequiresContext); } else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF32)) { encoding = Encoding.UTF32; serializer = new StringSerializerStrategy(Encoding.UTF32, SerializationContextRequirement.RequiresContext); } else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.UTF8)) { encoding = Encoding.UTF8; serializer = new StringSerializerStrategy(Encoding.UTF8, SerializationContextRequirement.RequiresContext); } else { throw new InvalidOperationException($"String had encoding flags but no specified encoding."); } } else { //If we have a context, but don't have an encoding context, then we should grab the default that uses ASCII serializer = serializerProviderService.Get <string>(); } bool shouldTerminate = !context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.DontTerminate); //If we shouldn't null terminate or if we're using a fixed/known size (meaning we never want to append a null terminator past the size) if (!shouldTerminate || context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize)) { serializer = new DontTerminateStringSerializerDecorator(serializer, encoding); } //It is possible that the WoW protocol expects a fixed-size string that both client and server know the length of //This can be seen in the first packet Auth_Challenge: uint8 gamename[4]; //It can be seen that this field is a fixed length string (byte array) if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize)) { //read the key. It will have the size int size = context.BuiltContextKey.Value.ContextSpecificKey.Key; serializer = new SizeStringSerializerDecorator(new FixedSizeStringSizeStrategy(context.BuiltContextKey.Value.ContextSpecificKey.Key), serializer, encoding); } //It is also possible that the WoW protocol expects a length prefixed string else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.SendSize)) { byte addedSize = (byte)(context.BuiltContextKey.Value.ContextSpecificKey.Key >> 4); //This is an odd choice but if they mark it with conflicting metdata maybe we should throw? switch ((SendSizeAttribute.SizeType)(context.BuiltContextKey.Value.ContextSpecificKey.Key & 0b0000_0000_0000_1111)) {
/// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context.TargetType == typeof(DateTime)) { return(new PackedDateTimeSerializerStrategyDecorator(serializerProviderService.Get <int>()) as ITypeSerializerStrategy <TType>); } if (context.TargetType == typeof(BitArray)) { return(new BitArraySerializerStrategyDecorator() as ITypeSerializerStrategy <TType>); } throw new InvalidOperationException($"Special decorator cannot handle {typeof(TType).FullName}."); }
//TODO: Refactor /// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } IChildKeyStrategy keyStrategy = null; //TODO: Check if we can get this from context? //Check the WireDataContract attribute for keysize information WireDataContractAttribute contractAttribute = typeof(TType).GetTypeInfo().GetCustomAttribute <WireDataContractAttribute>(false); //Build the strategy for child size and value read/write switch (contractAttribute.OptionalChildTypeKeySize) { //TODO: Make it a factory case WireDataContractAttribute.KeyType.Byte: keyStrategy = new GenericChildKeyStrategy <byte>(contractAttribute.TypeHandling, serializerProviderService.Get <byte>()); break; case WireDataContractAttribute.KeyType.Int32: keyStrategy = new GenericChildKeyStrategy <int>(contractAttribute.TypeHandling, serializerProviderService.Get <int>()); break; case WireDataContractAttribute.KeyType.UShort: keyStrategy = new GenericChildKeyStrategy <ushort>(contractAttribute.TypeHandling, serializerProviderService.Get <ushort>()); break; case WireDataContractAttribute.KeyType.None: default: throw new InvalidOperationException($"Encountered Type: {typeof(TType).FullName} that requires child type mapping but has provided {nameof(WireDataContractAttribute.KeyType)} Value: {contractAttribute.OptionalChildTypeKeySize} which is invalid."); } ITypeSerializerStrategy <TType> strat = null; //Depending on if we're flags or key return the right serializer decorator. if (typeof(TType).GetTypeInfo().GetCustomAttribute <WireDataContractBaseTypeByFlagsAttribute>(false) == null) { //Won't be null at this point. Should be a valid strategy. We also don't need to deal with context since there is only EVER 1 serializer of this type per type. strat = new SubComplexTypeSerializerDecorator <TType>(new LambdabasedDeserializationPrototyeFactory <TType>(), new MemberSerializationMediatorCollection <TType>(mediatorFactoryService).ToArray(), serializerProviderService, keyStrategy); } else { strat = new SubComplexTypeWithFlagsSerializerDecorator <TType>(new LambdabasedDeserializationPrototyeFactory <TType>(), new MemberSerializationMediatorCollection <TType>(mediatorFactoryService).ToArray(), serializerProviderService, keyStrategy); } //Check for compression flags if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.Compressed)) { strat = new CompressionTypeSerializerStrategyDecorator <TType>(strat, serializerProviderService.Get <uint>()); } return(strat); }
protected override IEnumerable <ISerializableTypeContext> TryGetAssociatedSerializableContexts(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //We need to include the potential default child type now IEnumerable <ISerializableTypeContext> contexts = new TypeMemberParsedTypeContextCollection(context.TargetType); contexts = contexts.Concat(context.TargetType.GetTypeInfo().GetCustomAttribute <DefaultChildAttribute>(false) != null ? new ISerializableTypeContext[] { new TypeBasedSerializationContext(context.TargetType.GetTypeInfo().GetCustomAttribute <DefaultChildAttribute>().ChildType) } : Enumerable.Empty <ISerializableTypeContext>()); //Grab the children from the metadata; return type contexts so the types can be handled (no context is required because the children are their own registerable type return(contexts.Concat(GetAssociatedChildren(context.TargetType).Select(t => new TypeBasedSerializationContext(t) as ISerializableTypeContext))); }
/// <inheritdoc /> protected override IEnumerable <ISerializableTypeContext> TryGetAssociatedSerializableContexts(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //We need context when we refer to the members of a Type. They could be marked with metadata that could cause a serializer to be context based return(new TypeMemberParsedTypeContextCollection(context.TargetType) .Concat(GetInheritanceHierarchy(context.TargetType).Where(t => t.GetTypeInfo().GetCustomAttribute <WireDataContractAttribute>(false) != null).Select(t => new TypeBasedSerializationContext(t)))); }