/// <summary> /// Invokes the specified context. /// </summary> public static object Invoke(CardServiceMethodInvokerInput input, Action <string> trace, string environment) { var invocationParameters = input.InvocationParameters; var targetType = input.TargetType; trace("Searching service interface..."); var serviceInterface = targetType.GetInterfaces().FirstOrDefault(i => i.Name.EndsWith("Service")); if (serviceInterface == null) { // find service implementation and find interface by using it serviceInterface = targetType.Assembly.GetTypes().FirstOrDefault(i => i.Name.EndsWith("Service")); if (serviceInterface == null) { throw new ArgumentNullException(nameof(serviceInterface)); } serviceInterface = serviceInterface.GetInterfaces().FirstOrDefault(i => i.Name.EndsWith("Service")); if (serviceInterface == null) { throw new ArgumentNullException(nameof(serviceInterface)); } } var requestedType = serviceInterface.FullName; var partAfterSetupCompleted = @" EverestContext.Current.AfterSetupCompleted(() => { var bindings = BindingFlags.NonPublic | BindingFlags.Instance; var container = (Container)EverestContext.Current.GetType().GetField(" + "\"_container\"" + @", bindings).GetValue(EverestContext.Current); container.Options.AllowOverridingRegistrations = true; container.RegisterLifetimeScope<" + targetType.FullName + @"," + targetType.FullName + @">(); container.RegisterLifetimeScope<" + serviceInterface.FullName + @">(() => container.GetInstance<" + targetType.FullName + @">()); }); "; if (targetType.IsGenericType) // maybe calling job definition { requestedType = $"{targetType.FullName.RemoveFromEnd("`1")}<{requestedType}>"; partAfterSetupCompleted = string.Empty; } var configFilePath = GetWebConfigFilePath(serviceInterface.AssemblyQualifiedName, environment); ChangeAppConfig(configFilePath); trace("Searching method in service..."); var method = targetType.GetMethods(AllBindings).FirstOrDefault(m => m.GetMethodNameWithSignature() == input.MethodName); if (method == null) { throw new ArgumentNullException(nameof(method)); } // interface has method if (!targetType.IsGenericType && serviceInterface.GetMethods(AllBindings).All(m => m.GetMethodNameWithSignature() != input.MethodName)) { requestedType = targetType.FullName; } trace("Accessing service method parameter type."); var methodName = input.MethodName.Substring(0, input.MethodName.IndexOf("(", StringComparison.Ordinal)); var parameterDefinitionPart = string.Empty; var parameterCallPart = string.Empty; var parameterInfoList = method.GetParameters(); if (parameterInfoList.Length > 0) { parameterDefinitionPart = string.Join(" ,", parameterInfoList.Select(p => $"{p.ParameterType.FullName} {p.Name}")); parameterCallPart = string.Join(" ,", parameterInfoList.Select(p => $"{p.Name}")); } MethodInfo methodInfo = null; { const string location = @"d:\boa\server\bin\"; var referencedAssemblies = new List <string> { "System.Core.dll", "mscorlib.dll", "System.dll", $"{location}BOA.Card.Core.dll", $"{location}BOA.Card.Contracts.dll", $"{location}BOA.Card.Contracts.Online.dll", $"{location}BOA.Card.Definitions.dll", $"{location}SimpleInjector.dll", $"{location}SimpleInjector.Extensions.LifetimeScoping.dll", $"{location}BOA.Card.Services.Batch.dll", $"{location}{targetType.Assembly.GetName().Name}.dll" }; var sourceCode = @" using BOA.Card.Core.ServiceBus; using System.Reflection; using SimpleInjector; namespace ApiInspector.Invoking.Dynamic { class ServiceWrapper { public static object Wrap(" + parameterDefinitionPart + @") { var methodName = " + "\"" + methodName + "\"" + @"; " + partAfterSetupCompleted + @" EverestContext.Current.Build(); EverestContext.Current.ContextHeader = EverestContext.Current.ContextHeader ?? new BOA.Card.Core.ServiceBus.ContextHeader{ Environment = " + '"' + EnvironmentInfo.Parse(environment) + '"' + @" }; using (BOA.Card.Core.ServiceBus.EverestContext.Current.BeginScope()) { var serviceInstance = EverestContext.Current.GetService<" + requestedType + @">(); var bindings = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static|BindingFlags.InvokeMethod; var realTypeOfService = typeof(" + requestedType + @"); var output = realTypeOfService.InvokeMember(methodName, bindings, null, serviceInstance, new object[] { " + parameterCallPart + @" }); var transactionContext = EverestContext.Current.GetService<TransactionContext>(); if (transactionContext.Exception != null) { throw transactionContext.Exception; } return output; } } } } "; var compilerParams = new CompilerParameters(referencedAssemblies.ToArray()) { CompilerOptions = "/target:library /optimize", GenerateExecutable = false, GenerateInMemory = true, IncludeDebugInformation = false }; trace("Started to compile..."); var results = CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(compilerParams, sourceCode); if (results.Errors.Count > 0) { trace("Compile fail."); var convertErrorsToException = Fun(() => { var errorMessage = new StringBuilder(); foreach (CompilerError compilerError in results.Errors) { errorMessage.AppendLine(compilerError.ToString()); } return(new ArgumentException(errorMessage.ToString())); }); throw convertErrorsToException(); } trace("Compile success."); var assembly = results.CompiledAssembly; methodInfo = assembly.GetType("ApiInspector.Invoking.Dynamic.ServiceWrapper").GetMethod("Wrap"); if (methodInfo == null) { throw new ArgumentNullException(nameof(methodInfo)); } } // invoke method { trace("Service invocation is started. Waiting response..."); var response = InvokeStaticMethod(methodInfo, invocationParameters.ToArray()); trace("Service invocation is success."); return(response); } }
/// <summary> /// Invokes the specified invocation information. /// </summary> static InvokeOutput UnsafeInvoke(BOAContext boaContext, Action <string> trace, InvocationInfo invocationInfo, IReadOnlyList <InvocationMethodParameterInfo> parameters) { var success = Fun((object responseOfInvokeMethod) => new InvokeOutput { ExecutionResponseAsJson = SerializeToJsonDoNotIgnoreDefaultValues(responseOfInvokeMethod) }); var findTargetType = Fun(() => { trace($"Started to search class: {invocationInfo.ClassName}"); return(GetTargetType(invocationInfo)); }); var targetType = findTargetType(); var tryToInvokeAsEndOfDay = Fun(() => { var methodName = invocationInfo.MethodName; if (methodName != EndOfDay.MethodAccessText) { return(null); } boaContext.Authenticate(ChannelContract.EOD); var errorMessage = EndOfDayInvoker.Invoke(targetType); if (errorMessage == null) { return(EODSuccess); } return(new InvokeOutput(new Exception(errorMessage))); }); var eodOutput = tryToInvokeAsEndOfDay(); if (eodOutput != null) { return(eodOutput); } trace($"Started to search method: {invocationInfo.MethodName}"); var methodInfo = targetType.GetMethods(AllBindings).FirstOrDefault(m => CecilHelper.IsSignatureMatched(m, invocationInfo.MethodName)); if (methodInfo == null) { throw new Exception("Method not found."); } // TRY BOA Authenticate if (IsBoaAuthenticationRequired(invocationInfo.AssemblyName)) { trace("Authentication is started. Because assembly name starts with BOA prefix."); // boaContext.Authenticate(); boaContext.LoadBOAConfigurationFile(); } trace("Preparing invocation parameters"); var invocationParameters = InvocationParameterPreparer.Prepare(parameters ?? new List <InvocationMethodParameterInfo>(), methodInfo, boaContext, trace); trace("Invoke started. Response waiting..."); var invokeMethod = Fun(() => { var tryInvokeStaticMethod = Fun(() => { if (!methodInfo.IsStatic) { return(TryMethodInvokeResponse.NotInvoked); } return(new TryMethodInvokeResponse(InvokeStaticMethod(methodInfo, invocationParameters.ToArray()))); }); var tryInvokeAsCardServiceMethod = Fun(() => { var methodName = invocationInfo.MethodName; if (!IsCardServiceAssembly(targetType.Namespace)) { return(TryMethodInvokeResponse.NotInvoked); } var cardServiceMethodInvokerInput = new CardServiceMethodInvokerInput(targetType, methodName, invocationParameters); return(new TryMethodInvokeResponse(CardServiceMethodInvoker.Invoke(cardServiceMethodInvokerInput, trace, invocationInfo.Environment))); }); var tryInvokeNonStaticMethod = Fun(() => { if (methodInfo.IsStatic) { return(TryMethodInvokeResponse.NotInvoked); } var instance = InstanceCreator.Create(targetType, boaContext); return(new TryMethodInvokeResponse(InvokeNonStaticMethod(methodInfo, instance, invocationParameters.ToArray()))); }); var tryMethodInvokeResponse = tryInvokeStaticMethod(); if (tryMethodInvokeResponse != TryMethodInvokeResponse.NotInvoked) { return(tryMethodInvokeResponse.MethodReturnValue); } tryMethodInvokeResponse = tryInvokeAsCardServiceMethod(); if (tryMethodInvokeResponse != TryMethodInvokeResponse.NotInvoked) { return(tryMethodInvokeResponse.MethodReturnValue); } tryMethodInvokeResponse = tryInvokeNonStaticMethod(); if (tryMethodInvokeResponse != TryMethodInvokeResponse.NotInvoked) { return(tryMethodInvokeResponse.MethodReturnValue); } throw new InvalidOperationException("Unknown invocation type."); }); var stopwatch = Stopwatch.StartNew(); var responseInvokeMethod = invokeMethod(); responseInvokeMethod = NormalizeInvokedMethodReturnValue(responseInvokeMethod); stopwatch.Stop(); trace($"Successfully invoked in {stopwatch.Elapsed.Milliseconds} milliseconds."); boaContext.Dispose(); var output = success(responseInvokeMethod); var serializeParameter = Fun((object instance) => { if (instance == null) { return(null); } return(SerializeToJson(instance)); }); output.InvocationParameters = invocationParameters.Select(serializeParameter).ToList(); return(output); }