Thread.CurrentThread.CurrentCulture不在线程池内的线程中工作

我有一个方法将在一个线程内调用,这些线程由线程池管理。 该方法调用DLL的方法,遗憾的是,该方法需要特定的语言环境才能正确执行。

在通过threadpool运行此方法之前,我已经在应用程序的主线程中运行时进行了测试,同时我手动管理线程并且工作正常,但是当我将其放入线程池内工作时,语言环境不会应用,因此该方法行为不正确。

以下是应该受区域设置更改影响的方法部分(但行为不正常):

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; 

这是线程池创建结构:

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

我也尝试将locale设置为如下所示的线程对象,但它没有解决问题:(第2行和第3行):

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

请指导我在线程池中运行此方法时应该如何获得正确的结果。

更新后的版本:

 this.isTerminated = false; Thread.Sleep(1000); while (!this.isTerminated) { Thread.Sleep(1000); IList 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  0) Thread.Sleep(50); } 

其他方法:

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

而这个单独的课程:

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

必须在线程调用的实际方法中应用文化。

一个简单的方法应该是在线程池中执行要在线程池上执行的方法,该方法在执行原始方法之前将从排队作业的线程中的CultureInfo应用到线程池线程,类似于:

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

鉴于该方法,您只需使用提交到线程池;

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

(感谢WaitCallback在下面的评论中指出WaitCallback

SendMessage方法中,您需要设置线程的当前文化和它的UICulture:

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

如果当前文化不是静态的,那么必须将它从调用线程传递给排队的工作线程。

在这种情况下,如果您控制它,我会向SMSTask类添加一个culture参数,如果没有,则添加一个包含SMSTask和文化的包装类,如果您不控制它并使用新类作为SendMessage方法的参数。

更新

这是另一个想法:如果SendMessage在主线程上下文中运行时正常工作,但更改文化不会影响在线程池中运行时的结果,问题可能是该方法从当前用户中选取信息。

您可以在排队线程池请求并将其作为参数传递给SendMessage方法之前保存当前标识来测试此理论:

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

SendMessage方法中,您可以检索调用线程的标识并模拟该用户,执行您的工作,然后撤消模拟:

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