我有一个将在线程内调用的方法,这些线程由线程池管理。 该方法调用DLL的方法,遗憾的是,该方法需要特定的语言环境才能正确执行。
在通过threadpool运行此方法之前,我已经在应用程序的主线程中运行时进行了测试,同时我手动管理线程并且工作正常,但是当我将它放入线程池中时,locale是未应用,因此该方法行为不正确。
以下是应该受区域设置更改影响的方法部分(但行为不正常):
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<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);
}
其他方法:
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");
}
}
答案 0 :(得分:2)
必须在线程调用的实际方法中应用文化。
一个简单的方法应该是在线程池中包含要执行的方法,该方法在执行原始方法之前将从排队作业的线程中的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);
(感谢Aidiakapi在下面的评论中指出WaitCallback
)
答案 1 :(得分:0)
在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();
}
}