我有一个WCF服务方法,它调用SQL存储过程。我正在使用IIS5进行开发(对此无能为力,II6/7不可用)
为了获得一些收益,我将对这个存储过程进行多次异步调用,方法是将调用放入一个c#TPL任务中。
当作为任务运行时,我得到一个SQL异常。。。"登录失败。登录来自不受信任的域,不能与Windows身份验证一起使用"
但是,如果我在不使用Task的情况下运行完全相同的进程,那么SQL连接就没有问题
在我看来,IIS虚拟文件夹(WCF)的凭据没有委派给任务?有什么想法我可以为TPL任务线程指定凭据吗?
我正在使用Windows身份验证(sspi)和模拟,以便能够连接到单独的SQL框。
感谢你的帮助。
您有两个选择。
1) 选择您的整个应用程序始终使用来流动身份
<runtime>
<alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>
这会产生开销的副作用,并有可能意外地使用当前调用用户的特权而不是应用程序标识执行一些意外代码。我个人会避免这种情况,选择第二个你明确选择加入的地方。
2) 在设置TPL任务之前捕获WindowsIdentity
,并使用Impersonate
+WindowsImpersonationContext
:显式模拟需要进行呼叫的位置
public void SomeWCFOperation()
{
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
Task.Factory.StartNew(() =>
{
// some unpriviledged code here
using(WindowsImpersonationContext impersonationContext = currentIdentity.Impersonate())
{
// this code will execute with the priviledges of the caller
}
// some more unpriviledged code here
});
}
作为另一种变通方法,您可以创建TPL的扩展,如下所示:
public static class TaskFactoryExtensions
{
public static Task StartNewImpersonated(this TaskFactory taskFactory, Action action)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew(() =>
{
using (identity.Impersonate())
{
action();
}
});
}
public static Task<TResult> StartNewImpersonated<TResult>(this TaskFactory taskFactory, Func<TResult> function)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew<TResult>(() =>
{
using (identity.Impersonate())
{
return function();
}
});
}
}
然后,您可以调用这些新方法来代替标准的StartNew方法。
这样做的缺点是有很多方法需要重写。