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> 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);
            }
        }