/// <summary> /// Creates an expression to convert incoming Stream to the customer method inputs. /// If customer method takes no inputs or only takes ILambdaContext, return null. /// </summary> /// <param name="customerSerializerInstance">Instance of lambda input & output serializer.</param> /// <param name="inStreamParameter">Input stream parameter.</param> /// <param name="iLambdaContextType">Type of context passed for the invocation.</param> /// <returns>Expression that deserializes incoming stream to the customer method inputs or null if customer method takes no input.</returns> /// <exception cref="LambdaValidationException">Thrown when customer method inputs don't meet lambda requirements.</exception> private Expression BuildInputExpressionOrNull(object customerSerializerInstance, Expression inStreamParameter, out Type iLambdaContextType) { Type inputType = null; iLambdaContextType = null; // get input types var inputTypes = _customerMethodInfo.GetParameters().Select(pi => pi.ParameterType).ToArray(); // check if there are too many parameters if (inputTypes.Length > 2) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.MethodTooManyParams, _customerMethodInfo.Name, _handler.TypeName); } // if two parameters, check that the second input is ILambdaContext if (inputTypes.Length == 2) { if (!Types.IsILambdaContext(inputTypes[1])) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.MethodSecondParamNotContext, _customerMethodInfo.Name, _handler.TypeName, Types.ILambdaContextTypeName); } iLambdaContextType = inputTypes[1]; inputType = inputTypes[0]; } // if one input, check if input is ILambdaContext else if (inputTypes.Length == 1) { if (Types.IsILambdaContext(inputTypes[0])) { iLambdaContextType = inputTypes[0]; } else { inputType = inputTypes[0]; } } if (inputType != null) { // deserializer.Deserialize(inStream) return(CreateDeserializeExpression(customerSerializerInstance, inputType, inStreamParameter)); } if (iLambdaContextType != null) { _logger.LogDebug($"UCL : Validating iLambdaContextType"); UserCodeValidator.ValidateILambdaContextType(iLambdaContextType); } return(null); }
/// <summary> /// Constructs an instance of the customer-specified serializer /// </summary> /// <param name="serializerAttribute">Serializer attribute used to define the input/output serializer.</param> /// <returns></returns> /// <exception cref="LambdaValidationException">Thrown when serializer doesn't satisfy serializer type requirements.</exception> /// <exception cref="LambdaUserCodeException">Thrown when failed to instantiate serializer type.</exception> private object ConstructCustomSerializer(Attribute serializerAttribute) { var attributeType = serializerAttribute.GetType(); var serializerTypeProperty = attributeType.GetTypeInfo().GetProperty("SerializerType"); if (serializerTypeProperty == null) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.InvalidClassNoSerializerType, attributeType.FullName); } if (!Types.TypeType.GetTypeInfo().IsAssignableFrom(serializerTypeProperty.PropertyType)) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.InvalidClassSerializerTypeWrongType, attributeType.FullName, Types.TypeType.FullName); } var serializerType = serializerTypeProperty.GetValue(serializerAttribute) as Type; if (serializerType == null) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.SerializerTypeNotSet, attributeType.FullName); } var serializerTypeInfo = serializerType.GetTypeInfo(); var constructor = serializerTypeInfo.GetConstructor(Type.EmptyTypes); if (constructor == null) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.SerializerMissingConstructor, serializerType.FullName); } var iLambdaSerializerType = serializerTypeInfo.GetInterface(Types.ILambdaSerializerTypeName); if (iLambdaSerializerType == null) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.InvalidClassNoILambdaSerializer, serializerType.FullName); } _logger.LogDebug($"UCL : Validating type '{iLambdaSerializerType.FullName}'"); UserCodeValidator.ValidateILambdaSerializerType(iLambdaSerializerType); object customSerializerInstance; customSerializerInstance = constructor.Invoke(null); return(customSerializerInstance); }
/// <summary> /// Constructs an instance of the customer type, or returns null /// if the customer method is static and does not require an object /// </summary> /// <param name="customerType">Type of the customer handler container.</param> /// <returns>Instance of customer handler container type</returns> /// <exception cref="LambdaUserCodeException">Thrown when failed to instantiate customer type.</exception> private object GetCustomerObject(Type customerType) { _logger.LogDebug($"UCL : Validating type '{_handler.TypeName}'"); UserCodeValidator.ValidateCustomerType(customerType, CustomerMethodInfo); var isHandlerStatic = CustomerMethodInfo.IsStatic; if (isHandlerStatic) { _logger.LogDebug($"UCL : Not constructing customer object, customer method is static"); _logger.LogDebug($"UCL : Running static constructor for type '{_handler.TypeName}'"); // Make sure the static initializer for the type runs now, during the init phase. RuntimeHelpers.RunClassConstructor(customerType.TypeHandle); return(null); } _logger.LogDebug($"UCL : Instantiating type '{_handler.TypeName}'"); return(Activator.CreateInstance(customerType)); }
/// <summary> /// Loads customer assembly, type, and method. /// After this call returns without errors, it is possible to invoke /// the customer method through the Invoke method. /// </summary> public void Init(Action <string> customerLoggingAction) { Assembly customerAssembly = null; try { _logger.LogDebug($"UCL : Parsing handler string '{_handlerString}'"); _handler = new HandlerInfo(_handlerString); // Set the logging action private field on the Amazon.Lambda.Core.LambdaLogger type which is part of the // public Amazon.Lambda.Core package when it is loaded. AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => { _logger.LogInformation($"UCL : Loaded assembly {args.LoadedAssembly.FullName} into default ALC."); if (!_customerLoggerSetUpComplete && string.Equals(LambdaCoreAssemblyName, args.LoadedAssembly.GetName().Name, StringComparison.Ordinal)) { _logger.LogDebug( $"UCL : Load context loading '{LambdaCoreAssemblyName}', attempting to set {Types.LambdaLoggerTypeName}.{LambdaLoggingActionFieldName} to logging action."); SetCustomerLoggerLogAction(args.LoadedAssembly, customerLoggingAction, _logger); _customerLoggerSetUpComplete = true; } }; _logger.LogDebug($"UCL : Attempting to load assembly '{_handler.AssemblyName}'"); customerAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(_handler.AssemblyName); } catch (FileNotFoundException fex) { _logger.LogError(fex, "An error occured on UCL Init"); throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.CouldNotFindHandlerAssembly, fex.FileName); } catch (LambdaValidationException validationException) { _logger.LogError(validationException, "An error occured on UCL Init"); throw; } catch (Exception exception) { _logger.LogError(exception, "An error occured on UCL Init"); throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.UnableToLoadAssembly, _handler.AssemblyName); } _logger.LogDebug($"UCL : Attempting to load type '{_handler.TypeName}'"); var customerType = customerAssembly.GetType(_handler.TypeName); if (customerType == null) { throw LambdaExceptions.ValidationException(Errors.UserCodeLoader.UnableToLoadType, _handler.TypeName, _handler.AssemblyName); } _logger.LogDebug($"UCL : Attempting to find method '{_handler.MethodName}' in type '{_handler.TypeName}'"); CustomerMethodInfo = FindCustomerMethod(customerType); _logger.LogDebug($"UCL : Located method '{CustomerMethodInfo}'"); _logger.LogDebug($"UCL : Validating method '{CustomerMethodInfo}'"); UserCodeValidator.ValidateCustomerMethod(CustomerMethodInfo); var customerObject = GetCustomerObject(customerType); var customerSerializerInstance = GetSerializerObject(customerAssembly); _logger.LogDebug($"UCL : Constructing invoke delegate"); var isPreJit = UserCodeInit.IsCallPreJit(); var builder = new InvokeDelegateBuilder(_logger, _handler, CustomerMethodInfo); _invokeDelegate = builder.ConstructInvokeDelegate(customerObject, customerSerializerInstance, isPreJit); if (isPreJit) { _logger.LogInformation("PreJit: PrepareDelegate"); RuntimeHelpers.PrepareDelegate(_invokeDelegate); } }