Beispiel #1
0
        private ConstructorInfo generateType(Guid id, IInterceptor interceptor, ConstructorInfo ctor)
        {
            if (interceptor == null)
            {
                throw new ArgumentNullException(nameof(interceptor));
            }

            var baseType         = ctor?.DeclaringType ?? throw new ArgumentNullException(nameof(ctor));
            var name             = baseType.Name;
            var genericNameIndex = name.IndexOf('`');

            if (genericNameIndex != -1)
            {
                name = name.Substring(0, genericNameIndex);
            }

            var settings = new ProxyAttribute();

            if (!settings.Enabled)
            {
                throw new NotSupportedException("This class does not support proxying.");
            }

            var typeBuilder = proxyModule.Value.DefineType($"ProxyFor{name}_{id.ToString().Replace("-", "")}",
                                                           TypeAttributes.Class |
                                                           TypeAttributes.Public |
                                                           TypeAttributes.AutoClass |
                                                           TypeAttributes.AnsiClass |
                                                           TypeAttributes.Sealed |
                                                           TypeAttributes.BeforeFieldInit,
                                                           baseType);

            var interceptorField = typeBuilder.DefineField("interceptor", typeof(IInterceptor),
                                                           FieldAttributes.Private | FieldAttributes.InitOnly);

            generateCtor(typeBuilder, interceptorField, ctor);

            if (baseType.GetMethods()
                .Where(methodInfo => methodInfo.DeclaringType != typeof(object) && methodInfo.IsVirtual && !methodInfo.IsGenericMethod)
                .Count(methodInfo => tryToOverrideMethod(settings, interceptor, typeBuilder, interceptorField, methodInfo)) == 0)
            {
                throw new ArgumentException($"Unable to proxy any member for this type: {baseType.FullName}");
            }

            return(typeBuilder.CreateTypeInfo().GetConstructors().Single());
        }
Beispiel #2
0
        private bool tryToOverrideMethod(ProxyAttribute settings, IInterceptor interceptor, TypeBuilder typeBuilder, FieldBuilder interceptorField, MethodInfo methodInfo)
        {
            settings = methodInfo.GetCustomAttribute <ProxyAttribute>() ?? settings;

            if (!settings.Enabled)
            {
                return(false);
            }

            var returnType = methodInfo.ReturnType;

            if (typeof(Task) == returnType)
            {
                returnType = typeof(void);
            }
            else if (typeof(Task).IsAssignableFrom(returnType))
            {
                if (!returnType.IsGenericType || returnType.GetGenericTypeDefinition() != typeof(Task <>))
                {
                    return(handleInvalidType(settings.InvalidTypeHandling, typeBuilder, methodInfo,
                                             $"Unable to create proxy class. Unknown Task return type for method: {methodInfo.Name}"));
                }
                returnType = returnType.GetGenericArguments().Single();
            }

            if (returnType != typeof(void) && !interceptor.Serializer.CanSerialize(returnType))
            {
                return(handleInvalidType(settings.InvalidTypeHandling, typeBuilder, methodInfo,
                                         $"Unable to create proxy class. Invalid return type for method: {methodInfo.Name}"));
            }

            var @params = methodInfo.GetParameters();

            if (@params.Any(param => param.IsOut || !interceptor.Serializer.CanSerialize(param.ParameterType)))
            {
                return(handleInvalidType(settings.InvalidTypeHandling, typeBuilder, methodInfo,
                                         $"Unable to create proxy class. Invalid argument type for method: {methodInfo.Name}"));
            }

            var methodBuilder = typeBuilder.DefineMethod(
                methodInfo.Name,
                methodInfo.Attributes,
                methodInfo.CallingConvention,
                methodInfo.ReturnType,
                @params.Select(param => param.ParameterType).ToArray());

            var il = methodBuilder.GetILGenerator();

            //load interceptor field
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, interceptorField);

            //load fire and forget boolean value
            var fireAndForget = settings.FireAndForget &&
                                (methodInfo.ReturnType == typeof(void) || methodInfo.ReturnType == typeof(Task));

            il.Emit(fireAndForget ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);

            //load method name
            il.Emit(OpCodes.Ldstr, methodInfo.Name);

            //load new tuple array
            if (@params.Length == 0)
            {
                // ReSharper disable once PossibleNullReferenceException
                il.Emit(OpCodes.Call, typeof(Array).GetMethod("Empty").MakeGenericMethod(typeof(Tuple <Type, object>)));
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, @params.Length);
                il.Emit(OpCodes.Newarr, typeof(Tuple <Type, object>));

                for (var index = 0; index < @params.Length; index++)
                {
                    il.Emit(OpCodes.Dup);

                    //load param index
                    il.Emit(OpCodes.Ldc_I4, index);

                    var param = @params[index];

                    //load typeof parameter
                    il.Emit(OpCodes.Ldtoken, param.ParameterType);
                    il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));

                    //load argument
                    il.Emit(OpCodes.Ldarg, index + 1);
                    il.Emit(OpCodes.Box, param.ParameterType);

                    //make tuple of parameter type and argument
                    il.Emit(OpCodes.Newobj, typeof(Tuple <Type, object>).GetConstructors().First());

                    //set tuple value to loaded index in the tuple array
                    il.Emit(OpCodes.Stelem_Ref);
                }
            }

            // ReSharper disable once PossibleNullReferenceException
            il.Emit(OpCodes.Callvirt, typeof(IInterceptor)
                    .GetMethod(nameof(IInterceptor.RemoteInvoke))
                    .MakeGenericMethod(returnType == typeof(void) ? typeof(object) : returnType));

            if (methodInfo.ReturnType == typeof(void))
            {
                il.Emit(OpCodes.Callvirt, typeof(Task).GetMethod(nameof(Task.Wait), Type.EmptyTypes));
            }
            else if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
            {
                // ReSharper disable once PossibleNullReferenceException
                il.Emit(OpCodes.Callvirt, typeof(Task <>).MakeGenericType(returnType).GetProperty("Result").GetMethod);
            }

            il.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);

            return(true);
        }