I have a method which will be called inside a thread and those threads are managed by threadpool. The method is calling a DLL's method which unfortunately requires a specific locale for being performed correctly.
Before puting this method to be ran by threadpool, I've tested it while running in application's main thread and also while I manually manage the threads and it works fine, but when I put it into work inside a threadpool, locale is not applied and consequently the method does not behave correctly.
Here is the part of the method which should be affected by locale change (but not behave well):
CultureInfo before = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("fa-IR");
int result = tsms.SendSMS(smsTask.MobileNumber.MobileNumberInString, smsTask.Message);
Thread.CurrentThread.CurrentUICulture = before;
and here is the threadpool creating structure:
foreach (SMSTask smsTask in tasksList)
{
if (this.threadsCount < this.threadPoolSize)
{
this.threadsCount++;
ThreadPool.QueueUserWorkItem(new WaitCallback(SendMessage), (object)smsTask);
}
}
I also tried setting locale to thread object like below but it didn't solve the problem: (line 2 and 3):
threadObject = new Thread(new ThreadStart(TaskProcessingThreadFunction));
threadObject.CurrentCulture = new CultureInfo("fa-IR");
threadObject.CurrentUICulture = new CultureInfo("fa-IR");
threadObject.Start();
Please guide me on how should I get the correct result while this method is being ran inside threadpool.
Updated Version:
this.isTerminated = false;
Thread.Sleep(1000);
while (!this.isTerminated)
{
Thread.Sleep(1000);
IList<SMSTask> tasksList = dataProvider.GetTasks(this.minimumRetryTimeInSeconds);
if (tasksList == null || tasksList.Count < 1)
continue;
singleTaskConsoleObject(" " + tasksList.Count + " task(s) fetched for sending.");
var cultureToUse = new System.Globalization.CultureInfo("fa-IR");
var currentThread = System.Threading.Thread.CurrentThread;
currentThread.CurrentCulture = cultureToUse;
currentThread.CurrentUICulture = cultureToUse;
var currentIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
foreach (SMSTask smsTask in tasksList)
{
if (this.threadsCount < this.threadPoolSize)
{
this.threadsCount++;
smsTask.Iden = currentIdentity;
ThreadPool.QueueUserWorkItem(new WaitCallback(SendMessage), (object)smsTask);
}
}
while (this.threadsCount > 0)
Thread.Sleep(50);
}
Other Methods:
private void SendMessage(object smsTask)
{
System.Security.Principal.WindowsImpersonationContext impersonationContext = null;
try
{
SMSTask smsTaskEntity = (SMSTask)smsTask;
impersonationContext = ((System.Security.Principal.WindowsIdentity)(smsTaskEntity.Iden)).Impersonate();
SmsSender smsSender = new SmsSender();
SMSSendingResponse response = smsSender.SendSMS(smsTaskEntity);
bool loggingResult = dataProvider.UpdateResponse(response);
singleTaskGridObject(response, loggingResult);
this.threadsCount--;
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
And this separate class:
public SMSSendingResponse SendSMS(SMSTask smsTask)
{
TSMSLIB_TLB.TSMS_Tooba tsms = new TSMS_Tooba();
SendingResult sendingResult = SendingResult.Initial_Condition;
try
{
System.Globalization.CultureInfo before = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("fa-IR");
string msg = string.Format(System.Threading.Thread.CurrentThread.CurrentCulture, smsTask.Message);
int result = tsms.SendSMS(smsTask.MobileNumber.MobileNumberInString, msg);
System.Threading.Thread.CurrentThread.CurrentUICulture = before;
if (result > 0)
{
return new SMSSendingResponse(smsTask, SMSDeclarations.SendingStatus.SentSuccessfully, result.ToString());
}
else
{
foreach (SendingResult sResult in Enum.GetValues(typeof(SendingResult)))
{
if (result == (int)sResult)
{
sendingResult = sResult;
}
}
return new SMSSendingResponse(smsTask, SMSDeclarations.SendingStatus.SendingFailed,
result.ToString(), sendingResult.ToString());
}
}
catch (Exception ex)
{
return new SMSSendingResponse(smsTask, SMSDeclarations.SendingStatus.SendingFailed,
"0".ToString(), "Exception occured");
}
}
Within your
SendMessage
method, you need to set both the thread's current culture and it's UICulture:If the current culture is not static, then you must pass it from the calling thread to the queued worker thread.
In this scenario, I would add a culture parameter to the
SMSTask
class if you control it or, if not, add a wrapper class that contains both the SMSTask and the culture to use if you do not control it and use the new class as the parameter to theSendMessage
method.Update
Here is another thought: if SendMessage works correctly while running in the main thread context, but changing the culture does not affect the results when running in a thread pool, the issue may be that the method picks information up from the current user.
You can test this theory by saving the current identity before queueing the threadpool request and passing as a parameter to your
SendMessage
method:Within the
SendMessage
method, you can retrieve the identity of the calling thread and impersonate that user, perform your work, then undo the impersonation:The culture must be applied inside the actual method called by the thread.
A simple way should be to wrap the method to be executed on the thread pool inside another method that applies the CultureInfo from the thread enqueuing the job to the thread pool thread before executing the original method, something like;
Given that method, you just submit to the threadpool using;
(thanks to Aidiakapi for pointing out
WaitCallback
in the comments below)