C# 在模拟时调用异步WCF服务
我在服务器上运行了一个WCF服务,该服务器配置为接受Kerberos身份验证 Kerberos工作正常,因此WCF服务知道哪个用户正在连接他。 该服务以异步方法提供一切。像这里这样(只是clearity的一个例子)C# 在模拟时调用异步WCF服务,c#,wcf,asynchronous,impersonation,C#,Wcf,Asynchronous,Impersonation,我在服务器上运行了一个WCF服务,该服务器配置为接受Kerberos身份验证 Kerberos工作正常,因此WCF服务知道哪个用户正在连接他。 该服务以异步方法提供一切。像这里这样(只是clearity的一个例子) publicExampleService:IEExampleService{ 公共任务GetUsernameAsync(){ 返回wait Task.Run(()=>System.Threading.Thread.CurrentPrincipal.Name); } } 在客户端,我
publicExampleService:IEExampleService{
公共任务GetUsernameAsync(){
返回wait Task.Run(()=>System.Threading.Thread.CurrentPrincipal.Name);
}
}
在客户端,我有一个控制器(这是一个MVC页面,但这并不重要),它异步调用这些方法
public ExampleController {
public async Task<ActionResult> Index() {
using(var serviceClient = ServiceFactory.GetServiceClient())
using(Security.Impersonation.Impersonate())
{
var data = await serviceClient.GetUsernameAsync();
return View(data);
}
}
}
公共示例控制器{
公共异步任务索引(){
使用(var serviceClient=ServiceFactory.GetServiceClient())
使用(Security.Impersonation.Impersonate())
{
var data=await serviceClient.getUsernameAync();
返回视图(数据);
}
}
}
只要我不使用wait,模拟效果就很好
由于Task
不流动模拟的身份,我想知道是否有可能,改变Task
的执行用户,或者做任何其他事情,使模拟在这个用例中工作
我尝试了一个定制的等待器(在这种情况下可以使用文化),但这根本不起作用(它也不模拟)。因为我负责WCF接口,所以这里有一个解决方案可以工作(但我不喜欢,因为它或多或少是代码重复):
[服务合同]
接口IExampleService{
[经营合同]
字符串GetUsername();
}
接口IExampleServiceAsync{
任务GetUserNameAsync();
}
类ExampleService:IEExampleService{
公共字符串GetUsername(){
返回System.Threading.Thread.CurrentPrincipal.Name;
}
}
类ExpampleServiceClient:ServiceClient,IExampleServiceAsync{
公共任务GetUsernameAsync(){
返回任务。运行(()=>GetUsername());
}
私有字符串GetUsername(){
使用(Security.Impersonation.Impersonate())
{
返回base.Proxy.GetUsername();
}
}
}
我不得不说,这是一种变通方法,而不是解决方案,它改变了服务器端的接口(仅限于非异步接口),但至少它是可行的
此解决方案还有一个优点-您可以在ExampleServiceClient上实现模拟作为行为模式。好的-经过更深入的研究,我终于找到了如何在异步任务中传递模拟windows身份的解决方案 该解决方案是机器范围的,将为所有(在本例中)64位ASP.NET 4.5应用程序设置 在
C:\Windows\Microsoft.Net\Framework64\v4.0.30319
中找到aspnet.config
文件(这可能也适用于更高版本),并将legacyImpersonationPolicy
的值更改为false
<legacyImpersonationPolicy enabled="false"/>
这里解释了aspnet.config设置(顺便说一句,在web.config文件中设置它是不起作用的)(它基本上说,如果这是真的,我们就用.NET 1.1的方法来做)
您可以使用此方法检查windows标识是否流动:
System.Security.SecurityContext.IsWindowsIdentityFlowSuppressed()
我不同意你的问题 问题不在于您的
等待
。但是你的任务。运行。实际上不应该有等待任务。在ASP.Net代码上运行。它的效果是不必要的线程切换。由于ASP.Net上没有STA线程,因此不需要这样做,这只会降低代码的速度
如果您坚持使用真正的无线程任务
s,您应该不会有任何问题,因为您将停留在单个线程中。除非您的应用程序服务器的客户机数量非常有限,并且CPU占用的操作数量巨大,否则多线程不利于扩展,因为单个用户可以快速填充服务器的时间表
您应该真正使用Task.FromResult
或TaskCompletionSource.Task
来确保保持单线程。顺便说一句,这将解决您的[ThreadLocal]
属性问题
TL:DR
不要使用任务。在服务器端运行。使用Task.FromResult
,这样您只有一个线程
编辑:响应
哪根线?在客户端,您仍将使用wait
。我从来没有说过不要使用等待。我说过不要直接在任务中使用wait
。运行(UI线程除外)。我没说你应该阻止线程。因为你的线程应该做一些工作来产生传递到任务中的结果。FromResult
。阻塞意味着线程什么也不做,同时消耗资源(即内存)。见鬼,根本没必要这么做
服务器端应使用以下模式:
public ExampleService : IExampleService
{
public Task<string> GetUsernameAsync()
{
var name = System.Threading.Thread.CurrentPrincipal.Name;
return Task.FromResult(name);
}
}
publicExampleService:IEExampleService
{
公共任务GetUsernameAsync()
{
var name=System.Threading.Thread.CurrentPrincipal.name;
返回Task.FromResult(名称);
}
}
客户应该留下来
public ExampleController
{
public async Task<ActionResult> Index()
{
using(var serviceClient = ServiceFactory.GetServiceClient())
using(Security.Impersonation.Impersonate())
{
var data = await serviceClient.GetUsernameAsync();
return View(data);
}
}
}
公共示例控制器
{
异步的公共异步任务样式。Task.Run
是异步的并发样式,仅当您需要使用另一个线程时才应使用(因为您是CPU绑定的,或者此线程需要用于其他用途).这意味着我宁愿阻塞线程长达5秒,而不是使用async和Wait?不。不应该发生任何阻塞。但同时,不应该不必要地发生线程切换。你应该阅读啊,现在我明白你的意思了,但是任务。在服务器端运行只是一个简单的解释。但你可能在这一点上是对的但我的问题不是关于服务器端-模拟在客户端的wait
上失败(或未流动)。
System.Security.SecurityContext.IsWindowsIdentityFlowSuppressed()
public ExampleService : IExampleService
{
public Task<string> GetUsernameAsync()
{
var name = System.Threading.Thread.CurrentPrincipal.Name;
return Task.FromResult(name);
}
}
public ExampleController
{
public async Task<ActionResult> Index()
{
using(var serviceClient = ServiceFactory.GetServiceClient())
using(Security.Impersonation.Impersonate())
{
var data = await serviceClient.GetUsernameAsync();
return View(data);
}
}
}