Skip to main content
Post Reopened by Billal BEGUERADJ, Sᴀᴍ Onᴇᴌᴀ
using statements added
Added to review
Source Link
raysefo
  • 267
  • 2
  • 12

Here is the IHostedServiceWorker:

public class Worker :using BackgroundService
{System.Data;
    private readonly ILogger<Worker>using _logger;System.Data.SqlClient;
    private readonly IHttpClientFactoryusing _httpClientFactory;System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using privateSystem.Net.Http.Json;
using readonlySystem.Text;
using IConfigurationPurchaseRazerCodesMultipleRequestService.Modal;
using _configuration;TrendyolGameCodeService.Modal;

    public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
    }

namespace PurchaseRazerCodesMultipleRequestService
{
   protected overridepublic asyncclass TaskWorker ExecuteAsync(CancellationToken: stoppingToken)BackgroundService
    {
        //Timer with 3 mins
        var timer = new PeriodicTimer(TimeSpan.FromMinutes(3));
        while (await timer.WaitForNextTickAsync(stoppingToken))
     private readonly ILogger<Worker> {_logger;
          private readonly awaitIHttpClientFactory GetData();_httpClientFactory;
            _logger.LogInformation("Worker runningprivate at:readonly {time}",IConfiguration DateTimeOffset.Now);_configuration;

        public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
        {
            _logger = logger;
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
        }
    }

    private async Task MakeRequestsToRemoteService(string productCode, long id)
    {
     protected override async ifTask ExecuteAsync(id <= 0) throw newCancellationToken ArgumentOutOfRangeException(nameof(id)stoppingToken);
        try
        {
            var httpClient = _httpClientFactory.CreateClient("RazerClient");

            //Token
            
            httpClient.DefaultRequestHeaders.Accept.Add(///Random Timer
            var timer = new PeriodicTimer(TimeSpan.FromMinutes(new MediaTypeWithQualityHeaderValueRandom("application/x-www-form-urlencoded").Next(1, 2)));
 
            var_logger.LogInformation("Timer: tokenContent{timer}", =DateTimeOffset.Now);
 new FormUrlEncodedContent          while (new[]await timer.WaitForNextTickAsync(stoppingToken))
            {
                new KeyValuePair<string,await string>GetData("username", "Test"),;
                new KeyValuePair<string, string>_logger.LogInformation("password", "123456")
            "Worker running at: {time}", DateTimeOffset.Now);
            });

            using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);}

        private async Task MakeRequestsToRemoteService(string productCode, long id, int amount, int bulkId)
        {
            if ((intid <= 0)tokenResponse.StatusCode ==throw 200new ArgumentOutOfRangeException(nameof(id));
            try
            {
                var tokenhttpClient = await tokenResponse.Content_httpClientFactory.ReadAsStringAsyncCreateClient("RazerClient");

                //Call Razer Multi Requests
                
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",Token
                    token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                #regionvar CalculatetokenContent quantity= new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("username", "Test"),
                    new KeyValuePair<string, string>("password", "+REyN-#V5!_DgUn+y%hVj7VmyhN^+?%y+Qxkc-bLZR6$uqsYV")
                });

                var num = amount;
               using var firstNumtokenResponse = 50;
                var secondNumawait =httpClient.PostAsync(_configuration["Token:Production"], 50;tokenContent);

                if (num(int)tokenResponse.StatusCode <== 100200)
                {
                    firstNum = (num + 1) / 2;
                   var secondNumtoken = num - firstNum;
               await }tokenResponse.Content.ReadAsStringAsync();

                #endregion    //Call Razer Multi Requests

                var quantities   httpClient.DefaultRequestHeaders.Authorization = new List<int>AuthenticationHeaderValue("Bearer",
 { firstNum, secondNum};
                var cts = new CancellationTokenSource( token);
                ParallelOptions parallelOptions = new httpClient.DefaultRequestHeaders.Accept.Add()
                {
        new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

           MaxDegreeOfParallelism = 2,
       #region Calculate quantity

           CancellationToken = cts.Token
       var num = amount;
      };
              var firstNum try= 50;
                {
    var secondNum = 50;

             await Parallel.ForEachAsync(quantities, parallelOptions, async    if (quantity,num ct)< =>100)
                    {
                        var contentfirstNum = new FormUrlEncodedContent(new[]
                        {
                            new KeyValuePair<string,num string>("productCode",+ productCode1),
                            new KeyValuePair<string, string>("quantity",/ quantity.ToString()),2;
                           secondNum new= KeyValuePair<string,num string>("clientTrxRef",- bulkId.ToString())firstNum;
                        });

                        using var response =
                            await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);#endregion

                    var quantities = new ifList<int> { firstNum, secondNum};
                    var cts = new CancellationTokenSource();
                    ParallelOptions parallelOptions = new(int)response
                    {
                        MaxDegreeOfParallelism = 2,
                        CancellationToken = cts.StatusCodeToken
 == 200                  };
                    try
                    {
                        await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                        {
                            var couponcontent = awaitnew responseFormUrlEncodedContent(new[]
                            {
                                new KeyValuePair<string, string>("productCode", productCode),
                                new KeyValuePair<string, string>("quantity", quantity.ContentToString()),
                                new KeyValuePair<string, string>("clientTrxRef", bulkId.ReadFromJsonAsync<Root>ToString(cancellationToken:))
 ct                           });

                            _loggerusing var response =
                                await httpClient.LogInformationPostAsync("REFERENCE ID_configuration["Razer:Production"], {referenceId}"content, coupon.ReferenceIdct);

                            if ((int)response.StatusCode == 200)
                            {
                                var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                                _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                                await UpdateData(id);
                            }
                            else
                            {
                                _logger.LogError("Purchase ServiceError: {statusCode}",
                                    (int)response.StatusCode);
                            }
                        });
                    }
                    catch (OperationCanceledException ex)
                    {
                        _logger.LogError("Operation canceled: {Message}",
                            ex.Message);
                    }
                }
                catch (OperationCanceledException ex)else
                {
                    _logger.LogError("Operation"Token canceledServiceError: {MessagestatusCode}",
                        ex(int)tokenResponse.MessageStatusCode);
                }

                
            }
            elsecatch (Exception e)
            {
                _logger.LogError("Token ServiceError"Error: {statusCodeError} ",
    e.Message);
                (int)tokenResponse.StatusCode);
            }
        }
        catch (Exception e)
        {
            _logger.LogError("Error: {Error} ", e.Message);
            throw;
        }
    }
    private async Task GetData()
    {
        var sw = Stopwatch.StartNew();
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        awaitprivate usingasync varTask commandGetData()
 = new SqlCommand     { 
 Connection = sqlConnection }        var sw = Stopwatch.StartNew();
        const string sql  var connString = @"Select_configuration["ConnectionStrings:Default"];
 TOP 1 Id, BulkId, Amount, ProductCode from BulkPurchases where status  await using var sqlConnection = 0";new SqlConnection(connString);
        command.CommandText = sql;  sqlConnection.Open();

            await using var command = new SqlCommand { Connection = sqlConnection };
            const string sql = @"Select TOP 1 Id, BulkPurchaseRequestId, Amount, ProductCode from BulkPurchases where status = 0 ORDER BY NEWID()";
            command.CommandText = sql;

        try
        {
            await using var reader = await command.ExecuteReaderAsync();
            while (reader.Read())try
            {
                await using var reader = await command.ExecuteReaderAsync();
                while (reader.Read())
                {
                    _logger.LogInformation(
                        "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                        reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                    await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0), reader.GetInt32(2),reader.GetInt32(1));
                }
            }
        }
        catch (SqlException exception)
            {
                _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
        sw.Stop();}

        _logger.LogInformation($"******** ELAPSED TIME: { sw.Elapsed.TotalSeconds} seconds ********"Stop();
    }

    private async Task UpdateData(long id)
    {
        var connString_logger.LogInformation($"******** =ELAPSED _configuration["ConnectionStringsTIME:Default"];
        await using var sqlConnection ={sw.Elapsed.TotalSeconds} newseconds SqlConnection(connString********");
        sqlConnection.Open();}

        awaitprivate usingasync varTask commandUpdateData(long =id)
 new SqlCommand { Connection = sqlConnection }; {
        const string sql  var connString = @"Update_configuration["ConnectionStrings:Default"];
 BulkPurchases set status = 1 where Id     await using var sqlConnection = @id";new SqlConnection(connString);
        command.CommandText = sql;  sqlConnection.Open();

            await using var command.Parameters.Add( = new SqlParameter("id",SqlCommand id)){ Connection = sqlConnection };
            const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
            command.CommandText = sql;

            command.Parameters.Add(new SqlParameter("id", id));

            try
            {
                await command.ExecuteNonQueryAsync();
            }
            catch (SqlException exception)
            {
                _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if 
 this exception is unexpected        }
        }
    }
}

Here is the IHostedService:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;

    public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        //Timer with 3 mins
        var timer = new PeriodicTimer(TimeSpan.FromMinutes(3));
        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            await GetData();
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

        }
    }

    private async Task MakeRequestsToRemoteService(string productCode, long id)
    {
        if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
        try
        {
            var httpClient = _httpClientFactory.CreateClient("RazerClient");

            //Token
            
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
 
            var tokenContent = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("username", "Test"),
                new KeyValuePair<string, string>("password", "123456")
                
            });

            using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);

            if ((int)tokenResponse.StatusCode == 200)
            {
                var token = await tokenResponse.Content.ReadAsStringAsync();

                //Call Razer Multi Requests
                
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                    token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                #region Calculate quantity

                var num = amount;
                var firstNum = 50;
                var secondNum = 50;

                if (num < 100)
                {
                    firstNum = (num + 1) / 2;
                    secondNum = num - firstNum;
                }

                #endregion

                var quantities = new List<int> { firstNum, secondNum};
                var cts = new CancellationTokenSource();
                ParallelOptions parallelOptions = new()
                {
                    MaxDegreeOfParallelism = 2,
                    CancellationToken = cts.Token
                };
                try
                {
                    await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                    {
                        var content = new FormUrlEncodedContent(new[]
                        {
                            new KeyValuePair<string, string>("productCode", productCode),
                            new KeyValuePair<string, string>("quantity", quantity.ToString()),
                            new KeyValuePair<string, string>("clientTrxRef", bulkId.ToString())
                        });

                        using var response =
                            await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);

                        if ((int)response.StatusCode == 200)
                        {
                            var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                            _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                            await UpdateData(id);
                        }
                        else
                        {
                            _logger.LogError("Purchase ServiceError: {statusCode}",
                                (int)response.StatusCode);
                        }
                    });
                }
                catch (OperationCanceledException ex)
                {
                    _logger.LogError("Operation canceled: {Message}",
                        ex.Message);
                }

                
            }
            else
            {
                _logger.LogError("Token ServiceError: {statusCode}",
                    (int)tokenResponse.StatusCode);
            }
        }
        catch (Exception e)
        {
            _logger.LogError("Error: {Error} ", e.Message);
            throw;
        }
    }
    private async Task GetData()
    {
        var sw = Stopwatch.StartNew();
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Select TOP 1 Id, BulkId, Amount, ProductCode from BulkPurchases where status = 0";
        command.CommandText = sql;


        try
        {
            await using var reader = await command.ExecuteReaderAsync();
            while (reader.Read())
            {
                _logger.LogInformation(
                    "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                    reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0));
            }
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
        sw.Stop();

        _logger.LogInformation($"******** ELAPSED TIME: {sw.Elapsed.TotalSeconds} seconds ********");
    }

    private async Task UpdateData(long id)
    {
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
        command.CommandText = sql;

        command.Parameters.Add(new SqlParameter("id", id));

        try
        {
            await command.ExecuteNonQueryAsync();
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
    }
}

Here is the Worker:

   using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using PurchaseRazerCodesMultipleRequestService.Modal;
using TrendyolGameCodeService.Modal;


namespace PurchaseRazerCodesMultipleRequestService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IConfiguration _configuration;

        public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
        {
            _logger = logger;
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            
            ///Random Timer
            var timer = new PeriodicTimer(TimeSpan.FromMinutes(new Random().Next(1, 2)));
            _logger.LogInformation("Timer: {timer}", DateTimeOffset.Now);
            while (await timer.WaitForNextTickAsync(stoppingToken))
            {
                await GetData();
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            }
        }

        private async Task MakeRequestsToRemoteService(string productCode, long id, int amount, int bulkId)
        {
            if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
            try
            {
                var httpClient = _httpClientFactory.CreateClient("RazerClient");

                //Token

                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                var tokenContent = new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("username", "Test"),
                    new KeyValuePair<string, string>("password", "+REyN-#V5!_DgUn+y%hVj7VmyhN^+?%y+Qxkc-bLZR6$uqsYV")
                });

                using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);

                if ((int)tokenResponse.StatusCode == 200)
                {
                    var token = await tokenResponse.Content.ReadAsStringAsync();

                    //Call Razer Multi Requests

                    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                        token);
                    httpClient.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                    #region Calculate quantity

                    var num = amount;
                    var firstNum = 50;
                    var secondNum = 50;

                    if (num < 100)
                    {
                        firstNum = (num + 1) / 2;
                        secondNum = num - firstNum;
                    }

                    #endregion

                    var quantities = new List<int> { firstNum, secondNum};
                    var cts = new CancellationTokenSource();
                    ParallelOptions parallelOptions = new()
                    {
                        MaxDegreeOfParallelism = 2,
                        CancellationToken = cts.Token
                    };
                    try
                    {
                        await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                        {
                            var content = new FormUrlEncodedContent(new[]
                            {
                                new KeyValuePair<string, string>("productCode", productCode),
                                new KeyValuePair<string, string>("quantity", quantity.ToString()),
                                new KeyValuePair<string, string>("clientTrxRef", bulkId.ToString())
                            });

                            using var response =
                                await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);

                            if ((int)response.StatusCode == 200)
                            {
                                var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                                _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                                await UpdateData(id);
                            }
                            else
                            {
                                _logger.LogError("Purchase ServiceError: {statusCode}",
                                    (int)response.StatusCode);
                            }
                        });
                    }
                    catch (OperationCanceledException ex)
                    {
                        _logger.LogError("Operation canceled: {Message}",
                            ex.Message);
                    }
                }
                else
                {
                    _logger.LogError("Token ServiceError: {statusCode}",
                        (int)tokenResponse.StatusCode);
                }
            }
            catch (Exception e)
            {
                _logger.LogError("Error: {Error} ", e.Message);
                
            }
        }

        private async Task GetData()
        { 
            var sw = Stopwatch.StartNew();
            var connString = _configuration["ConnectionStrings:Default"];
            await using var sqlConnection = new SqlConnection(connString);
            sqlConnection.Open();

            await using var command = new SqlCommand { Connection = sqlConnection };
            const string sql = @"Select TOP 1 Id, BulkPurchaseRequestId, Amount, ProductCode from BulkPurchases where status = 0 ORDER BY NEWID()";
            command.CommandText = sql;

            
            try
            {
                await using var reader = await command.ExecuteReaderAsync();
                while (reader.Read())
                {
                    _logger.LogInformation(
                        "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                        reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                    await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0), reader.GetInt32(2),reader.GetInt32(1));
                }
            }
            catch (SqlException exception)
            {
                _logger.LogError("Error: {Error} ", exception.Message);
                
            }

            sw.Stop();

            _logger.LogInformation($"******** ELAPSED TIME: {sw.Elapsed.TotalSeconds} seconds ********");
        }

        private async Task UpdateData(long id)
        {
            var connString = _configuration["ConnectionStrings:Default"];
            await using var sqlConnection = new SqlConnection(connString);
            sqlConnection.Open();

            await using var command = new SqlCommand { Connection = sqlConnection };
            const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
            command.CommandText = sql;

            command.Parameters.Add(new SqlParameter("id", id));

            try
            {
                await command.ExecuteNonQueryAsync();
            }
            catch (SqlException exception)
            {
                _logger.LogError("Error: {Error} ", exception.Message);
                 
            }
        }
    }
}
Left closed in review as "Original close reason(s) were not resolved" by Toby Speight, Sᴀᴍ Onᴇᴌᴀ
Title changed and online game code explanation added at the bottom
Source Link
raysefo
  • 267
  • 2
  • 12

Background service for reducing the dependency on the user and the total time spent Retrieving large batches of online game codes?

Online game codes are used for purchasing items in online games

Background service for reducing the dependency on the user and the total time spent

Retrieving large batches of online game codes?

Online game codes are used for purchasing items in online games

clarification
Added to review
Source Link
raysefo
  • 267
  • 2
  • 12
public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;

    public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        //Timer with 3 mins
        var timer = new PeriodicTimer(TimeSpan.FromMinutes(3));
        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            await GetData();
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

        }
    }

    private async Task MakeRequestsToRemoteService(string productCode, long id)
    {
        if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
        try
        {
            var httpClient = _httpClientFactory.CreateClient("RazerClient");

            //Token
            
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

            var tokenContent = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("username", "Test"),
                new KeyValuePair<string, string>("password", "123456")
                
            });

            using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);

            if ((int)tokenResponse.StatusCode == 200)
            {
                var token = await tokenResponse.Content.ReadAsStringAsync();

                //Call Razer Multi Requests
                
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                    token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                #region Calculate quantity

                var quantitiesnum = newamount;
 List<int> { 100, 100, 100, 100,          var firstNum = 50;
                var secondNum = 50;

                if (num < 100)
                {
                    firstNum = (num + 1) / 2;
                    secondNum = num - firstNum;
                }

                #endregion

                var quantities = new List<int> { firstNum, secondNum};
                var cts = new CancellationTokenSource();
                ParallelOptions parallelOptions = new()
                {
                    MaxDegreeOfParallelism = 2,
                    CancellationToken = cts.Token
                };
                try
                {
                    await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                    {
                        var content = new FormUrlEncodedContent(new[]
                        {
                            new KeyValuePair<string, string>("productCode", productCode),
                            new KeyValuePair<string, string>("quantity", quantity.ToString()),
                            new KeyValuePair<string, string>("clientTrxRef", bulkId.ToString())
                        });

                        using var response =
                            await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);

                        if ((int)response.StatusCode == 200)
                        {
                            var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                            _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                            await UpdateData(id);
                        }
                        else
                        {
                            _logger.LogError("Purchase ServiceError: {statusCode}",
                                (int)response.StatusCode);
                        }
                    });
                }
                catch (OperationCanceledException ex)
                {
                    _logger.LogError("Operation canceled: {Message}",
                        ex.Message);
                }

                
            }
            else
            {
                _logger.LogError("Token ServiceError: {statusCode}",
                    (int)tokenResponse.StatusCode);
            }
        }
        catch (Exception e)
        {
            _logger.LogError("Error: {Error} ", e.Message);
            throw;
        }
    }
    private async Task GetData()
    {
        var sw = Stopwatch.StartNew();
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Select TOP 1 Id, BulkId, Amount, ProductCode from BulkPurchases where status = 0";
        command.CommandText = sql;


        try
        {
            await using var reader = await command.ExecuteReaderAsync();
            while (reader.Read())
            {
                _logger.LogInformation(
                    "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                    reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0));
            }
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
        sw.Stop();

        _logger.LogInformation($"******** ELAPSED TIME: {sw.Elapsed.TotalSeconds} seconds ********");
    }

    private async Task UpdateData(long id)
    {
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
        command.CommandText = sql;

        command.Parameters.Add(new SqlParameter("id", id));

        try
        {
            await command.ExecuteNonQueryAsync();
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
    }
}

Edit

I have written a ASP.NET Core Web API that retrieves game codes from another external API. The process works like this: the game code and the number of codes to be retrieved are sent in the request. However, there is a restriction in the external API I am retrieving the game codes from, which is that only 10 game codes can be retrieved in one request. This process is currently being done in various chain stores' cash registers. Only one game code purchase transaction is made from the cash register.

However, there can be customers who want to bulk retrieve thousands of game codes online. To achieve this, I added a new method to the API to enable multiple purchases by looping. The requests are sent to the external API in small pieces, with 10 being the requested amount of game codes. This process works without any problems because each successful request and response is recorded in the database. This process is carried out through the ASP.NET Core interface and has a limitation: if the user inputs the amount of game codes requested through the interface, it takes a long time to retrieve thousands of game codes as the maximum is 100 (to avoid time-out issues, etc.).

To improve this situation, I created a worker service that operates in the background. The user inputs the total request through the web interface, which is converted into 100s and recorded in the database. The worker service retrieves these requests one by one randomly, then sends the requests to the API I created and then to the external API. The new process in the worker service is as follows: when 100 game code requests are made, the maximum parallelism is 2 and they are sent in Parallel.ForEachAsync, divided into 50/50. The requests are processed in the manner described in 10s, as previously mentioned. My concern here is if 100 game codes are successfully sent and retrieved, I update the related record in the database. However, if an error occurs somewhere in the process of processing the external API in 10s, my API will return a 500 error. I'm not exactly sure whether the Parallel.ForEachAsync will continue processing the other requests or if the operation will be cancelled. I was unable to test this scenario. What logic would be appropriate to construct here? Especially for the update scenario. Is there a way to mock the service in order to get errors once in a while so that I can test the logic?

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;

    public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        //Timer with 3 mins
        var timer = new PeriodicTimer(TimeSpan.FromMinutes(3));
        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            await GetData();
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

        }
    }

    private async Task MakeRequestsToRemoteService(string productCode, long id)
    {
        if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
        try
        {
            var httpClient = _httpClientFactory.CreateClient("RazerClient");

            //Token
            
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

            var tokenContent = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("username", "Test"),
                new KeyValuePair<string, string>("password", "123456")
                
            });

            using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);

            if ((int)tokenResponse.StatusCode == 200)
            {
                var token = await tokenResponse.Content.ReadAsStringAsync();

                //Call Razer Multi Requests
                
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                    token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                var quantities = new List<int> { 100, 100, 100, 100, 100 };
                var cts = new CancellationTokenSource();
                ParallelOptions parallelOptions = new()
                {
                    MaxDegreeOfParallelism = 2,
                    CancellationToken = cts.Token
                };
                try
                {
                    await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                    {
                        var content = new FormUrlEncodedContent(new[]
                        {
                            new KeyValuePair<string, string>("productCode", productCode),
                            new KeyValuePair<string, string>("quantity", quantity.ToString())

                        });

                        using var response = await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);

                        if ((int)response.StatusCode == 200)
                        {
                            var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                            _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                            await UpdateData(id);
                        }
                        else
                        {
                            _logger.LogError("Purchase ServiceError: {statusCode}",
                                (int)response.StatusCode);
                        }
                    });
                }
                catch (OperationCanceledException ex)
                {
                    _logger.LogError("Operation canceled: {Message}",
                        ex.Message);
                }

                
            }
            else
            {
                _logger.LogError("Token ServiceError: {statusCode}",
                    (int)tokenResponse.StatusCode);
            }
        }
        catch (Exception e)
        {
            _logger.LogError("Error: {Error} ", e.Message);
            throw;
        }
    }
    private async Task GetData()
    {
        var sw = Stopwatch.StartNew();
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Select TOP 1 Id, BulkId, Amount, ProductCode from BulkPurchases where status = 0";
        command.CommandText = sql;


        try
        {
            await using var reader = await command.ExecuteReaderAsync();
            while (reader.Read())
            {
                _logger.LogInformation(
                    "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                    reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0));
            }
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
        sw.Stop();

        _logger.LogInformation($"******** ELAPSED TIME: {sw.Elapsed.TotalSeconds} seconds ********");
    }

    private async Task UpdateData(long id)
    {
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
        command.CommandText = sql;

        command.Parameters.Add(new SqlParameter("id", id));

        try
        {
            await command.ExecuteNonQueryAsync();
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
    }
}
public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;

    public Worker(ILogger<Worker> logger, IHttpClientFactory httpClientFactory, IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        //Timer with 3 mins
        var timer = new PeriodicTimer(TimeSpan.FromMinutes(3));
        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            await GetData();
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

        }
    }

    private async Task MakeRequestsToRemoteService(string productCode, long id)
    {
        if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
        try
        {
            var httpClient = _httpClientFactory.CreateClient("RazerClient");

            //Token
            
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

            var tokenContent = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("username", "Test"),
                new KeyValuePair<string, string>("password", "123456")
                
            });

            using var tokenResponse = await httpClient.PostAsync(_configuration["Token:Production"], tokenContent);

            if ((int)tokenResponse.StatusCode == 200)
            {
                var token = await tokenResponse.Content.ReadAsStringAsync();

                //Call Razer Multi Requests
                
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                    token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                #region Calculate quantity

                var num = amount;
                var firstNum = 50;
                var secondNum = 50;

                if (num < 100)
                {
                    firstNum = (num + 1) / 2;
                    secondNum = num - firstNum;
                }

                #endregion

                var quantities = new List<int> { firstNum, secondNum};
                var cts = new CancellationTokenSource();
                ParallelOptions parallelOptions = new()
                {
                    MaxDegreeOfParallelism = 2,
                    CancellationToken = cts.Token
                };
                try
                {
                    await Parallel.ForEachAsync(quantities, parallelOptions, async (quantity, ct) =>
                    {
                        var content = new FormUrlEncodedContent(new[]
                        {
                            new KeyValuePair<string, string>("productCode", productCode),
                            new KeyValuePair<string, string>("quantity", quantity.ToString()),
                            new KeyValuePair<string, string>("clientTrxRef", bulkId.ToString())
                        });

                        using var response =
                            await httpClient.PostAsync(_configuration["Razer:Production"], content, ct);

                        if ((int)response.StatusCode == 200)
                        {
                            var coupon = await response.Content.ReadFromJsonAsync<Root>(cancellationToken: ct);

                            _logger.LogInformation("REFERENCE ID: {referenceId}", coupon.ReferenceId);

                            await UpdateData(id);
                        }
                        else
                        {
                            _logger.LogError("Purchase ServiceError: {statusCode}",
                                (int)response.StatusCode);
                        }
                    });
                }
                catch (OperationCanceledException ex)
                {
                    _logger.LogError("Operation canceled: {Message}",
                        ex.Message);
                }

                
            }
            else
            {
                _logger.LogError("Token ServiceError: {statusCode}",
                    (int)tokenResponse.StatusCode);
            }
        }
        catch (Exception e)
        {
            _logger.LogError("Error: {Error} ", e.Message);
            throw;
        }
    }
    private async Task GetData()
    {
        var sw = Stopwatch.StartNew();
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Select TOP 1 Id, BulkId, Amount, ProductCode from BulkPurchases where status = 0";
        command.CommandText = sql;


        try
        {
            await using var reader = await command.ExecuteReaderAsync();
            while (reader.Read())
            {
                _logger.LogInformation(
                    "Order {Id}, {BulkId}, {Amount}, {ProductCode}",
                    reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3));

                await MakeRequestsToRemoteService(reader.GetString(3).Trim(), reader.GetInt32(0));
            }
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
        sw.Stop();

        _logger.LogInformation($"******** ELAPSED TIME: {sw.Elapsed.TotalSeconds} seconds ********");
    }

    private async Task UpdateData(long id)
    {
        var connString = _configuration["ConnectionStrings:Default"];
        await using var sqlConnection = new SqlConnection(connString);
        sqlConnection.Open();

        await using var command = new SqlCommand { Connection = sqlConnection };
        const string sql = @"Update BulkPurchases set status = 1 where Id = @id";
        command.CommandText = sql;

        command.Parameters.Add(new SqlParameter("id", id));

        try
        {
            await command.ExecuteNonQueryAsync();
        }
        catch (SqlException exception)
        {
            _logger.LogError("Error: {Error} ", exception.Message);
            throw; // Throw exception if this exception is unexpected
        }
    }
}

Edit

I have written a ASP.NET Core Web API that retrieves game codes from another external API. The process works like this: the game code and the number of codes to be retrieved are sent in the request. However, there is a restriction in the external API I am retrieving the game codes from, which is that only 10 game codes can be retrieved in one request. This process is currently being done in various chain stores' cash registers. Only one game code purchase transaction is made from the cash register.

However, there can be customers who want to bulk retrieve thousands of game codes online. To achieve this, I added a new method to the API to enable multiple purchases by looping. The requests are sent to the external API in small pieces, with 10 being the requested amount of game codes. This process works without any problems because each successful request and response is recorded in the database. This process is carried out through the ASP.NET Core interface and has a limitation: if the user inputs the amount of game codes requested through the interface, it takes a long time to retrieve thousands of game codes as the maximum is 100 (to avoid time-out issues, etc.).

To improve this situation, I created a worker service that operates in the background. The user inputs the total request through the web interface, which is converted into 100s and recorded in the database. The worker service retrieves these requests one by one randomly, then sends the requests to the API I created and then to the external API. The new process in the worker service is as follows: when 100 game code requests are made, the maximum parallelism is 2 and they are sent in Parallel.ForEachAsync, divided into 50/50. The requests are processed in the manner described in 10s, as previously mentioned. My concern here is if 100 game codes are successfully sent and retrieved, I update the related record in the database. However, if an error occurs somewhere in the process of processing the external API in 10s, my API will return a 500 error. I'm not exactly sure whether the Parallel.ForEachAsync will continue processing the other requests or if the operation will be cancelled. I was unable to test this scenario. What logic would be appropriate to construct here? Especially for the update scenario. Is there a way to mock the service in order to get errors once in a while so that I can test the logic?

Post Closed as "Needs details or clarity" by Toby Speight, pacmaninbw, slepic
clarify 3rd party web API quantity limit
Source Link
raysefo
  • 267
  • 2
  • 12
Loading
commented out code deleted
Source Link
raysefo
  • 267
  • 2
  • 12
Loading
added 154 characters in body
Source Link
raysefo
  • 267
  • 2
  • 12
Loading
The aim of my project is to reduce the dependency on the user and reduce the total time spent with the service in the background.
Source Link
raysefo
  • 267
  • 2
  • 12
Loading
update wording, break up long paragraph into two
Source Link
Loading
removed unnecesary information from question name
Link
Loading
Source Link
raysefo
  • 267
  • 2
  • 12
Loading