private void tryExecuteCommand()
        {
            if (!TW.Graphics.Keyboard.IsKeyPressed(Key.Return))
            {
                return;
            }
            if (Text == "")
            {
                return;
            }

            var output = provider.Execute(Text);

            output.Split('\n').ForEach(WriteLine);

            Text = "";
        }
        private async Task <SpCallResult> InvokeCore2(SpCall spCall, InvokeOptionsInternal spi)
        {
            //fix isLocal for system request and loopback
            if (spi.IsSystem)
            {
                spi.SpInvokeParams.IsLocalRequest = true;
            }

            // retrieve user session
            var invokeParams  = spi.SpInvokeParams;
            var invokeOptions = spi.SpInvokeParams.ApiInvokeOptions;
            var userSession   = _sessionManager.GetUserSession(invokeParams.AuthUserId, invokeParams.Audience);

            //Verify user request limit
            VerifyUserRequestLimit(userSession);

            //find api
            var spName = spCall.Method;

            if (spCall.Method == "System_api")
            {
                return(await Help());
            }

            var spInfo = await FindSpInfo(spName);

            if (spInfo == null)
            {
                var ex = new DirectSpException($"Could not find the API: {spName}");
                _logger?.LogWarning(ex.Message, ex);//Log exception
                throw ex;
            }

            //check IsCaptcha by meta-data
            if ((spInfo.ExtendedProps.CaptchaMode == SpCaptchaMode.Always || spInfo.ExtendedProps.CaptchaMode == SpCaptchaMode.Auto) && !spi.IsCaptcha)
            {
                throw new InvalidCaptchaException(await _captchaController.Create(), spInfo.ProcedureName);
            }

            //check IsBatchAllowed by meta-data
            if (!spInfo.ExtendedProps.IsBatchAllowed && spi.IsBatch)
            {
                throw new SpBatchIsNotAllowedException(spInfo.ProcedureName);
            }

            //Create DirectSpContext
            var context = new DirectSpContext()
            {
                IsBatch          = spi.IsBatch,
                IsCaptcha        = spi.IsCaptcha,
                RecordIndex      = invokeOptions.RecordIndex,
                RecordCount      = invokeOptions.RecordCount,
                AppVersion       = AppVersion,
                IsReadonlyIntent = spInfo.ExtendedProps.DataAccessMode == SpDataAccessMode.Read || spInfo.ExtendedProps.DataAccessMode == SpDataAccessMode.ReadSnapshot,
                RequestRemoteIp  = spi.SpInvokeParams.RequestRemoteIp?.ToString(),
                IsLocalRequest   = spi.SpInvokeParams.IsLocalRequest,
                UserAgent        = spi.SpInvokeParams.UserAgent,
                AppName          = AppName,
                Audience         = invokeParams.Audience,
                AuthUserId       = invokeParams.AuthUserId,
                ClientVersion    = null, //not implemented yet
                AgentContext     = userSession.AgentContext
            };

            //Get Connection String caring about ReadScale
            var isReadScale = IsReadScale(spInfo, userSession, spi, out bool isWriteMode);

            //create SqlParameters
            var spCallResults = new SpCallResult();
            var paramValues   = new Dictionary <string, object>();

            //set other caller params
            var spCallParams = spCall.Params ?? new Dictionary <string, object>();

            foreach (var spCallparam in spCallParams)
            {
                var paramName  = spCallparam.Key;
                var paramValue = spCallparam.Value;

                //find sqlParam for callerParam
                var spParam = spInfo.Params.FirstOrDefault(x => x.ParamName.Equals($"{paramName}", StringComparison.OrdinalIgnoreCase));
                if (spParam == null)
                {
                    throw new ArgumentException($"parameter '{paramName}' does not exists!");
                }
                spInfo.ExtendedProps.Params.TryGetValue(spParam.ParamName, out SpParamInfoEx spParamEx);

                //make sure Context has not been set by the caller
                if (paramName.Equals("Context", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException($"You can not set '{paramName}' parameter!");
                }

                // extract data from actual signed data
                var value = CheckJwt(paramValue, spParam, spParamEx);

                // convert data for db
                paramValue = ConvertDataForResource(value, spParam, spParamEx, invokeOptions);

                // add parameter
                paramValues.Add(paramName, paramValue);
            }

            // set all output value which have not been set yet
            foreach (var spParam in spInfo.Params)
            {
                if (spParam.IsOutput)
                {
                    if (string.Equals(spParam.ParamName, "Recordset", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new DirectSpException($"{spInfo.ProcedureName} contains {spParam.ParamName} as a output parameter which is not supported!");
                    }

                    if (!paramValues.ContainsKey(spParam.ParamName))
                    {
                        paramValues.Add(spParam.ParamName, Undefined.Value);
                    }
                }
            }

            // execute the command
            var commandResult = await _commandProvider.Execute(spInfo, context, paramValues, isReadScale);

            // store agentContext
            userSession.AgentContext = commandResult.AgentContext;

            // fill Recordset and close dataReader BEFORE reading sqlParameters
            if (commandResult.Table != null)
            {
                ReadRecordset(spCallResults, commandResult.Table, spInfo, invokeOptions);
            }

            // build return params
            foreach (var outParam in commandResult.OutParams)
            {
                var outParamName  = outParam.Key;
                var outParamValue = outParam.Value;
                var spParam       = spInfo.Params.FirstOrDefault(x => x.ParamName.Equals($"{outParamName}", StringComparison.OrdinalIgnoreCase));
                spInfo.ExtendedProps.Params.TryGetValue(outParamName, out SpParamInfoEx spParamEx);

                // Sign text if is need
                if (spParamEx?.SignType == SpSignType.JwtByCertThumb)
                {
                    outParamValue = _tokenSigner.Sign(outParamValue.ToString());
                }

                // convert data form result
                var value = ConvertDataFromResource(outParamValue, invokeOptions);
                spCallResults.Add(outParamName, value);

                // add Alternative Calendar
                if (_alternativeCalendar.IsDateTime(spParam.SystemTypeName.ToString()))
                {
                    spCallResults.Add(_alternativeCalendar.GetFieldName(outParamName), _alternativeCalendar.FormatDateTime(value, spParam.SystemTypeName));
                }
            }

            userSession.SetWriteMode(isWriteMode);
            return(spCallResults);
        }