public async Task <SpCallResult> Invoke(SpCall spCall, InvokeOptions spInvokeParams, bool isSystem = false) { if (spCall == null) { throw new ArgumentNullException(nameof(spCall)); } // Check duplicate request var spInfo = await FindSpInfo($"{spCall.Method}"); if (spInfo != null && spInfo.ExtendedProps.DataAccessMode == SpDataAccessMode.Write) { await CheckDuplicateRequest(spInvokeParams.ApiInvokeOptions.RequestId, spInfo.ExtendedProps.CommandTimeout); } // Call main invoke var spi = new InvokeOptionsInternal { SpInvokeParams = spInvokeParams, IsSystem = isSystem }; if (isSystem) { spi.SpInvokeParams.AuthUserId = AppAuthUserId; } return(await Invoke(spCall, spi)); }
public async Task <SpCallResult[]> Invoke(SpCall[] spCalls, InvokeOptions spInvokeParams) { //Check DuplicateRequest if spCalls contian at least one write foreach (var spCall in spCalls) { var spInfo = await FindSpInfo($"{spCall.Method}"); if (spInfo != null && spInfo.ExtendedProps.DataAccessMode == SpDataAccessMode.Write) { await CheckDuplicateRequest(spInvokeParams.ApiInvokeOptions.RequestId, 3600 * 2); break; } } var spi = new InvokeOptionsInternal { SpInvokeParams = spInvokeParams, IsBatch = true }; var spCallResults = new List <SpCallResult>(); var tasks = new List <Task <SpCallResult> >(); foreach (var spCall in spCalls) { tasks.Add(Invoke(spCall, spi)); } try { await Task.WhenAll(tasks.ToArray()); } catch { // catch await single exception } foreach (var item in tasks) { if (item.IsCompleted) { spCallResults.Add(item.Result); } else { spCallResults.Add(new SpCallResult { { "error", DirectSpExceptionAdapter.Convert(item.Exception.InnerException, _captchaController).SpCallError } }); } } return(spCallResults.ToArray()); }
private async Task <SpCallResult> Invoke(SpCall spCall, InvokeOptionsInternal spi) { try { return(await InvokeCore(spCall, spi)); } catch (SpInvokerAppVersionException) { await RefreshApi(); return(await Invoke(spCall, spi)); } catch (DirectSpException spException) //catch any read-only errors { throw spException.SpCallError.ErrorId == 3906 ? new SpMaintenanceReadOnlyException(spCall.Method) : spException; } }
private bool IsReadScale(SpInfo spInfo, UserSession userSession, InvokeOptionsInternal spi, out bool isWriteMode) { //Select ReadOnly Or Write Connection var dataAccessMode = spInfo.ExtendedProps != null ? spInfo.ExtendedProps.DataAccessMode : SpDataAccessMode.Write; //Write procedures cannot be called in ForceReadOnly anyway if (spi.IsForceReadOnly && dataAccessMode == SpDataAccessMode.Write) { throw new SpMaintenanceReadOnlyException(spInfo.ProcedureName); } //Set write request isWriteMode = !spi.IsForceReadOnly && dataAccessMode == SpDataAccessMode.Write; // Find connection string var isReadScale = spi.IsForceReadOnly || dataAccessMode == SpDataAccessMode.ReadSnapshot || (dataAccessMode == SpDataAccessMode.Read && userSession.LastWriteTime.AddSeconds(_readonlyConnectionSyncInterval) < DateTime.Now); return(isReadScale); }
private async Task <SpCallResult> InvokeCore(SpCall spCall, InvokeOptionsInternal spi) { try { // Check captcha await CheckCaptcha(spCall, spi); // Call core var result = await InvokeCore2(spCall, spi); // Update result await UpdateRecodsetDownloadUri(spCall, spi, result); return(result); } catch (Exception ex) { throw DirectSpExceptionAdapter.Convert(ex, _captchaController); } }
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); }