0

I am working on an ASP.NET Webform project (legacy code).On my button_click event i am sending sms message to all the datas populated in this.

 var customerSMS = BusinessLayer.SMS.SmsSetup.GetAllCustomerSMS(OfficeId);

This takes around 15seconds to do all the computing and get the data(1000rows)

from the Db.And for each data it runs through the loop and does validation and

sends the sms and it does take time.I want to do this task in background and

redirect the user to the index page and the background process continues till it

gets out of the loop.I am new to this and still learning this beautiful

language C#.I did go through this amazing Asynchronous Programming async/await

and Multithreading approach and got hold of it only in simple WindowsForm

applications.Any reference/code snippet/best approach with a simple explanation for my case would be helpful.

My button click event code :

    protected void ReturntoDashboard_Click(object sender, EventArgs e)
    { 

         sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
         if (sms.EnableSmsData && sms.SmsCount > 0)
         {
         #region Loan Section
           var smsLoan = Everest.Net.BusinessLayer.SMS.SmsSetup.GetLoanId(s.Sms_AccountNumber);
          var loanId =
             BusinessLayer.SMS.SmsSetup.GetLoanIdValue(s.Sms_AccountNumber);
             var dateexceeded =
             BusinessLayer.SMS.SmsSetup.IsDateExceeded(loanId);
             if (smsLoan != null && dateexceeded == true)
                 {
                  foreach (Common.SMS.SMSSetup sm in smsLoan)
                    {           

                        var smsClosingBalanceLoan = BusinessLayer.SMS.SmsSetup.GetAmountForLoanAlert(  sm.LoanId,
                                                                BusinessLayer.Core.DateConversion
                                                                    .GetCurrentServerDate()
                                                                    .AddDays(sms.DaysbeforeLoanalerts).ToString());

                   if (smsClosingBalanceLoan != null)
                       {
                         if (smsClosingBalanceLoan.LoanAmountToPay > 0)
                           {
                             int smsSentAlertCount = sms.LoanAlertCount;
                                var logCount = BusinessLayer.SMS.SmsSetup.GetLoanSmsAlertSentCount(DateTime.Now.AddDays(-smsSentAlertCount).ToString("yyyy-MM-dd"), DateTime.Now.ToString("yyyy-MM-dd"), sm.LoanAccountNumber);
                                  if (logCount < smsSentAlertCount)
                                     {
                                      smsLog = new Everest.Net.Common.SMS.SMSSetup();
                                          finalMessage = "Dear Member, Your Loan accnt " + sm.LoanAccountNumber + " with Principal"+ "+" + "Int Amnt: Rs." + smsClosingBalanceLoan.LoanAmountToPay + " need to be payed.Thank You," + officeName.OfficeName;

                                             smsLog.LogServiceType = "Loan";
                                             smsLog.LogSmsType = s.Sms_SmsType;
                                             smsLog.LogSmsMessage = finalMessage;
                                             smsLog.LogCustomerId = s.CustomerId.ToString();
                                             smsLog.LogAccountNumber = s.Sms_AccountNumber;
                                             smsLog.LogAccountType = s.Sms_AccountType;
                                             smsLog.LogSmsSentDate = BusinessLayer.Core.DateConversion.GetCurrentServerDate();
                                             smsLog.LogSmsFailedDate = "";
                                             smsLog.LogSentStatus = true;
                                             smsLog.LogUserId = UserId;
                                             smsLog.LogSmsFailedMessage = "";
                                             try
                                              {
                                                 var result = Everest.Net.BusinessLayer.SMS.smsParameters.SendSMS(sms.FromNum, sms.Token, sms.Url, cellNum, finalMessage);
                                              }
                                             catch (Exception ex)
                                              {
                                                  smsLog.LogSmsFailedDate = System.DateTime.Now.ToString("MM/dd/yyyy HHmmss");
                                                  smsLog.LogSentStatus = false;
                                                  smsLog.LogSmsFailedMessage = ex.Message;
                                                  Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
                                              }
                                              sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
                                              sms.SmsCount = sms.SmsCount - 1;
                                              Everest.Net.BusinessLayer.SMS.SmsSetup.UpdateSmsSetup(sms);
                                              Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
                                        }
                                    }
                               }
                          }
                   }


             }

     }
 }
  catch (Exception ex)
OLDMONK
  • 382
  • 2
  • 7
  • 25
  • 1
    How about making an Ajax call instead of a postback, so you don't have to redirect, just wait for the answer. – hardkoded Jun 26 '17 at 19:38
  • @kblok hello sir..what i want is after the button click event i want to redirect the user to the index page and do the sms sending work in background..like you said with ajax call instead of postback..i didnt get that part. – OLDMONK Jun 26 '17 at 19:49

1 Answers1

2

The ideal solution would remove the responsibility of sending the SMS from the web application itself. Instead, the web application should create a database record containing the message and recipient addresses, and a separate background job (e.g. a Windows Service) should poll the database and send SMS messages when neeeded. This is the best solution in terms of fault tolerance and auditability, because there is a permanent record of the messaging job which can be resumed if the system fails.

That being said, maybe you don't want to go to all that trouble. If you feel strongly that you wish to send the SMS directly from the ASP.NET application, you will need to create a Task and queue it to run using QueueBackgroundWorkitem. You will need to refactor your code a bit.

  1. Move all the logic for sending the SMS into a separate function that accepts all the information needed as parameters. For example,

    static void SendSMS(string[] addresses, string messagetext)
    {
        //Put your SMS code here
    }
    
  2. When you need to call the function, queue it as a background item

    HostingEnvironment.QueueBackgroundWorkItem(a => SendSMS(addresses, messageText)); 
    
  3. If your worker task needs to access its own cancellation token (e.g. if it is supposed to loop until cancelled), it is passed as an argument to the lambda expression. So you could modify the prototype

     static void SendSMS(string[] addresses, string messagetext, CancellationToken token)
     {
          while (!token.IsCancellationRequested) 
          {
              //Put your code here
          }
     }
    

    and pass it thus:

    HostingEnvironment.QueueBackgroundWorkItem(token => SendSMS(addresses, messageText, token));
    

Placing the task in the background queue ensures that ASP.NET keeps track of the thread, doesn't try to garbage collect it, and shuts it down properly when the application pool needs to shut down.

After queuing the background operation, your page can render is content per usual and conclude the HTTP response while the task continues to execute.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • thanks sir..but isnt this possible with asynchronous prog?like using async/await?just a thought and i am still newbie to it – OLDMONK Jun 26 '17 at 19:52
  • `Async` tasks are not guaranteed to complete unless you `await` them. But if you `await` the task then the page can't complete its processing and you're back where you started. Think you need a separate thread for this. – John Wu Jun 26 '17 at 19:55
  • Yes, especially since you want to perform a redirect, [which will abort the current thread](https://stackoverflow.com/questions/2777105/why-response-redirect-causes-system-threading-threadabortexception) in a very messy way. You don't want your SMS code to be interrupted by a `ThreadAbortException`. – John Wu Jun 26 '17 at 20:05
  • like you posted in your answer above,any links for the same workflow would be helpful..thank you – OLDMONK Jun 26 '17 at 20:09