예제 #1
0
        private MessageTypeHandler <T> BuildMessageTypeHandler <T>(BaseTypeRegistration baseTypeRegistration)
        {
            Type messageType      = typeof(T);
            var  typeRegistration = (TypeRegistration <T>)baseTypeRegistration;

            var descriptorProperty = messageType.GetProperties(BindingFlags.Public | BindingFlags.Static)
                                     .FirstOrDefault(x => x.Name == "Descriptor");

            var descriptor = (MessageDescriptor)descriptorProperty.GetValue(null);
            var fields     = descriptor.Fields.InFieldNumberOrder();

            var fieldByFieldNumber = fields
                                     .Select((field) => new KeyValuePair <int, FieldDescriptor>(field.FieldNumber, field))
                                     .ToDictionary(x => x.Key, x => x.Value);

            var idParameter     = Expression.Parameter(typeof(ulong), "identity");
            var entityParameter = Expression.Parameter(messageType, "entity");
            var factory         = Expression.Lambda <Func <ulong, T> >(typeRegistration.FactoryExpressionBuilder(idParameter), idParameter).Compile();
            var keyGetter       = Expression.Lambda <Func <T, ulong> >(typeRegistration.KeyGetterExpressionBuilder(entityParameter), entityParameter).Compile();

            return(new MessageTypeHandler <T>()
            {
                TypeRegistration = typeRegistration,
                Factory = factory,
                KeyGetter = keyGetter,
                FieldsByParameterNumber = fields
                                          .Where(x => string.Compare(x.Name, baseTypeRegistration.KeyMember.Name, true) != 0)
                                          .Select(FieldHandlerBuilder(typeRegistration))
                                          .ToDictionary(x => x.Key, x => x.Value)
            });
        }
        private void SetTypeRegistrationForType(BaseTypeRegistration registration)
        {
            var reflectedMethod = typeof(SchemaRegistry)
                                  .GetMethod($"{nameof(SchemaRegistry.SetTypeRegistrationForTypeGeneric)}", PrivateInstance)
                                  .MakeGenericMethod(registration.Type);

            reflectedMethod.Invoke(this, new object[] { registration });
        }
        private void SetTypeRegistrationForTypeGeneric <T>(BaseTypeRegistration registrationInfo)
        {
            var type = typeof(T);
            var keyedRegistrationInfo = registrationInfo as TypeRegistration <T>;
            Func <Expression, Expression> keyGetterExpressionBuilder;
            Func <Expression, Expression> factoryExpressionBuilder;
            MemberInfo keyMember = registrationInfo.KeyMember;

            if (keyedRegistrationInfo != null)
            {
                if (keyMember == null || keyedRegistrationInfo.KeyGetterExpressionBuilder == null || keyedRegistrationInfo.FactoryExpressionBuilder == null)
                {
                    throw new InvalidOperationException(
                              $"If you provide a custom {nameof(TypeRegistration<int>.KeyGetterExpressionBuilder)} "
                              + $"or {nameof(TypeRegistration<int>.KeyGetterExpressionBuilder)}, you must include both, as well as "
                              + $"the {nameof(TypeRegistration<int>.KeyMember)} parameter."
                              );
                }
                keyGetterExpressionBuilder = keyedRegistrationInfo.KeyGetterExpressionBuilder;
                factoryExpressionBuilder   = keyedRegistrationInfo.FactoryExpressionBuilder;
            }
            else
            {
                try
                {
                    var constructor = type.GetConstructors().First(x => x.GetParameters().Count() == 0);
                    keyMember = keyMember != null ? keyMember : (MemberInfo)type.GetProperty("Id");
                    var constructInstance = Expression.New(constructor);

                    keyGetterExpressionBuilder = (parameter) => Expression.PropertyOrField(parameter, "Id");
                    factoryExpressionBuilder   = (parameter) => Expression.MemberInit(constructInstance, Expression.Bind(keyMember, parameter));
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException(
                              $"Unable to create {nameof(keyGetterExpressionBuilder)} and {nameof(factoryExpressionBuilder)}  for type {type.FullName}. "
                              + $"Either give it a ulong property named `Id` or specify getter and setter with an IKeyedTypeRegistration.",
                              ex
                              );
                }
            }

            var registration = new TypeRegistration <T>()
            {
                Type        = type,
                TypeId      = registrationInfo.TypeId,
                AggregateId = registrationInfo.AggregateId,
                KeyMember   = keyMember,
                KeyGetterExpressionBuilder = keyGetterExpressionBuilder,
                FactoryExpressionBuilder   = factoryExpressionBuilder,
            };

            ByType <T> .Value = registration;
        }
예제 #4
0
        private Func <FieldDescriptor, int, KeyValuePair <ushort, FieldHandler> > FieldHandlerBuilder(BaseTypeRegistration typeRegistration)
        {
            return((discriptor, fieldIndex) =>
            {
                var messageType = typeRegistration.Type;
                var titleCaseName = $"{discriptor.Name.Substring(0, 1).ToUpper()}{discriptor.Name.Substring(1)}";
                var property = messageType.GetProperty(titleCaseName);

                Type propertyOuterType = null;
                Type propertyType;
                var isRepeated = property.PropertyType.GetTypeInfo().IsGenericType
                    ? property.PropertyType.GetGenericTypeDefinition() == typeof(RepeatedField <>)
                    : false;

                if (isRepeated)
                {
                    propertyOuterType = property.PropertyType;
                    propertyType = propertyOuterType.GetGenericArguments()[0];
                }
                else
                {
                    propertyType = property.PropertyType;
                }
                var isReference = typeof(IMessage).IsAssignableFrom(propertyType);
                var isPrimitive = _primitiveSerializers.ContainsKey(propertyType);

                if (!isReference && !isPrimitive)
                {
                    throw new InvalidOperationException($"Unable to find a primitive serializer for type {property.PropertyType.FullName}.");
                }

                var definition = new FieldHandlerDefinition()
                {
                    FieldDescriptor = discriptor,
                    MessageTypeRegistration = typeRegistration,
                    Property = property,
                    MessageType = messageType,
                    PropertyOuterType = propertyOuterType,
                    PropertyType = propertyType,
                    IsReference = isReference,
                    IsRepeated = isRepeated,
                    PrimitiveSerializer = isPrimitive ? _primitiveSerializers[propertyType] : null
                };

                FieldHandler toReturn;
                if (isReference)
                {
                    var buildBuildReferenceField = typeof(ProtobufDatomSerializer)
                                                   .GetMethod($"{nameof(ProtobufDatomSerializer.BuildReferenceField)}", PrivateInstance)
                                                   .MakeGenericMethod(messageType, propertyType);

                    toReturn = buildBuildReferenceField.Invoke(this, new object[] { definition }) as FieldHandler;
                }
                else
                {
                    var buildBuildSimpleField = typeof(ProtobufDatomSerializer)
                                                .GetMethod($"{nameof(ProtobufDatomSerializer.BuildSimpleField)}", PrivateInstance)
                                                .MakeGenericMethod(messageType, propertyType);

                    toReturn = buildBuildSimpleField.Invoke(this, new object[] { definition }) as FieldHandler;
                }

                Func <byte[], string> debugDeserializer;
                if (isPrimitive)
                {
                    var valueParameter = Expression.Parameter(typeof(byte[]), "value");
                    var deserialize = _primitiveSerializers[propertyType].GetDeserializeExpression(valueParameter);
                    var toStringMethod = propertyType.GetMethods().First(x => x.Name == "ToString");
                    var deserializeToString = Expression.Call(deserialize, toStringMethod);
                    debugDeserializer = Expression.Lambda <Func <byte[], string> >(deserializeToString, valueParameter).Compile();
                }
                else
                {
                    debugDeserializer = (value) => BitConverter.ToUInt64(value, 0).ToString();
                }

                _debugFormatters[new Tuple <ushort, ushort>(typeRegistration.TypeId, (ushort)discriptor.FieldNumber)] = (datom) => {
                    var valueFormat = isReference ? $"{propertyType.Name}[{{0}}]" : "{0}";
                    var fieldArrayIndex = isRepeated ? $"[{datom.ParameterArrayIndex}]": string.Empty;
                    return $"TX[{datom.TransactionId}] {datom.Action} {typeRegistration.Type.Name}[{datom.Identity}]"
                    + $".{discriptor.Name}{fieldArrayIndex} = {string.Format(valueFormat, debugDeserializer(datom.Value))}";
                };

                return new KeyValuePair <ushort, FieldHandler>((ushort)discriptor.FieldNumber, toReturn);
            });
        }