Thread.CurrentThread.CurrentCulture does not work in a thread inside a thread

I have a method that will be called inside a thread, and these threads are controlled by threadpool. This method calls the DLL method, which, unfortunately, requires the correct execution of a specific locale.

Before using this method to start threadpool, I tested it while working in the main thread of the application, as well as when manually managing threads, and it works fine, but when I put it into work in threadpool, locale does not apply, and therefore The method behaves incorrectly.

Here is part of the method that a locale change should affect (but should 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 flow creation structure:

 foreach (SMSTask smsTask in tasksList) { if (this.threadsCount < this.threadPoolSize) { this.threadsCount++; ThreadPool.QueueUserWorkItem(new WaitCallback(SendMessage), (object)smsTask); } } 

I also tried setting the locale for the object stream, as shown below, but this did not solve the problem: (lines 2 and 3):

 threadObject = new Thread(new ThreadStart(TaskProcessingThreadFunction)); threadObject.CurrentCulture = new CultureInfo("fa-IR"); threadObject.CurrentUICulture = new CultureInfo("fa-IR"); threadObject.Start(); 

Tell me how can I get the correct result while this method runs 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"); } } 
+6
source share
2 answers

Culture must be applied within a real method called flow.

A simple way would be to combine the method that should be executed in the thread pool inside another method that applies CultureInfo from the thread that forces the job to the thread pool thread before executing the original method, for example:

 private static WaitCallback PropagateCulture(WaitCallback action) { var currentCulture = Thread.CurrentThread.CurrentCulture; var currentUiCulture = Thread.CurrentThread.CurrentUICulture; return (x) => { Thread.CurrentThread.CurrentCulture = currentCulture; Thread.CurrentThread.CurrentUICulture = currentUiCulture; action(x); }; } 

Given this method, you just send to threadpool with;

 ThreadPool.QueueUserWorkItem(PropagateCulture(SendMessage), (object)smsTask); 

(thanks to Aidiakapi for pointing out WaitCallback in the comments below)

+2
source

In your SendMessage method, you need to set both the current thread culture and UICulture:

 var cultureToUse = new System.Globalization.CultureInfo("fa-IR"); var currentThread = System.Threading.Thread.CurrentThread; currentThread.CurrentCulture = cultureToUse; currentThread.CurrentUICulture = cultureToUse; 

If the current culture is not static, you must pass it from the calling thread to the workflow queue.

In this case, I will add a culture parameter to the SMSTask class if you control it, or if not, add a wrapper class containing both SMSTask and a culture to use if you do not control it and do not use the new class as a parameter of the SendMessage method .

Update

Here is another thought: if SendMessage works correctly while working in the context of the main thread, but changing the culture does not affect the results when it starts in the thread pool, the problem may be that the method selects information from the current user.

You can test this theory by storing the current identity before the threadpool request queue and passing it as a parameter to your SendMessage method:

 var currentIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); // ToDo: Store current identity in a parameter for SendMessage 

As part of the SendMessage method, you can get the identifier of the calling thread and impersonate this user, do the work, and then cancel the impersonation:

  System.Security.Principal.WindowsImpersonationContext impersonationContext = null; try { // Get the current identity from the SendMessage parameter and use it to impersonate that user on this thread impersonationContext = currentIdentity.Impersonate(); // Do work } finally { // Undo the impersonation if (impersonationContext != null) { impersonationContext.Undo(); } } 
0
source

All Articles