C# Thread.CurrentPrincipal未在WCF客户端回调中持久化
我有一个通过netTcpBinding的双工WCF服务,该服务使用订阅模式,其中客户端 将通过使用subscribe/Unsubscribe方法的回调实现来订阅服务 该服务有一个自定义的IAuthorizationPolicy,用于从数据库和 在IAuthorizationPolicy.Evaluate()方法中将默认线程主体设置为自定义主体 该服务在IIS 7.5中作为服务运行,位于LOCALSYSTEM标识下的Windows 7 首先,以下是客户端(WinForms)如何对用户进行身份验证:C# Thread.CurrentPrincipal未在WCF客户端回调中持久化,c#,multithreading,wcf,wcf-security,wcf-callbacks,C#,Multithreading,Wcf,Wcf Security,Wcf Callbacks,我有一个通过netTcpBinding的双工WCF服务,该服务使用订阅模式,其中客户端 将通过使用subscribe/Unsubscribe方法的回调实现来订阅服务 该服务有一个自定义的IAuthorizationPolicy,用于从数据库和 在IAuthorizationPolicy.Evaluate()方法中将默认线程主体设置为自定义主体 该服务在IIS 7.5中作为服务运行,位于LOCALSYSTEM标识下的Windows 7 首先,以下是客户端(WinForms)如何对用户进行身份验证:
更新:如果我将securityMode和clientCredentialType设置为“无”,主体将按预期传播,显然这与安全配置有关,我尝试了很多配置组合,但都没有成功
更新:我已经包括了一份复制该问题的报告 该解决方案是直接配置和运行的,只需点击几次,占用您宝贵的几分钟时间,它包含5个项目:
- 在计算机上启用以下windows功能及其父功能(如果尚未启用): Windows通信基础HTTP激活和Windows 通信基础非HTTP激活,启用WCF和 net.tcp
- 将在TrustedPeople存储中创建和添加服务证书
- 将为将收听的服务创建网站:7359 (http)和7357(net.tcp)
- 将在LOCALSYSTEM标识下创建应用程序池(以避免 测试期间的许可问题)
- 将在c:\inetpub\WCFCallbackSample中创建一个文件夹,并将服务输出复制到其中
- 从TrustedPeople存储中删除服务证书
- 卸载服务网站
- 删除网站文件夹
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IFinanceServiceCallback))]
public interface IFinanceService : IServiceContract, ISupportCallback // <-- Interface that defines Subscribe and Unsubscribe methods
{
[OperationContract]
void DuplexMessageTest(string text);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class FinanceService : IFinanceService
{
// Subscription boilerplate code
private static readonly
DuplexServiceSubscriptionManager<IFinanceServiceCallback> _subscriptionManager = new DuplexServiceSubscriptionManager<IFinanceServiceCallback>();
public bool Subscribe()
{
return _subscriptionManager.Subscribe();
}
public bool Unsubscribe()
{
return _subscriptionManager.Unsubscribe();
}
// A test method for simulation
public void DuplexMessageTest(string text)
{
_subscriptionManager.InvokeCallbackMethod(callback => callback.OnDuplexTest(text));
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single, AutomaticSessionShutdown=true)]
public class FinanceServiceCallbackSubscription : BaseServiceSubscription<IFinanceService>, IFinanceServiceCallback
{
public FinanceServiceCallbackSubscription() : base()
{
}
public delegate void DuplexTestEventHandler(string message);
public event DuplexTestEventHandler DuplexTest;
public void OnDuplexTest(string message)
{
-->> At this point, the Thread.CurrentPrincipal is reset <<--
if (DuplexTest != null)
DuplexTest(message);
}
}
- 构建解决方案
- 使用InstallService.bat安装服务
- 调试/运行解决方案以运行两个服务使用者 (客户端\广播机,客户端\侦听器)
- 从广播公司发送消息
- 在侦听器中,您将注意到回调线程标识 (打印在控制台上)与主线程的标识不同 由SetThreadPrincipal在应用程序启动时设置
起始邮政编码: 服务接口:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IFinanceServiceCallback))]
public interface IFinanceService : IServiceContract, ISupportCallback // <-- Interface that defines Subscribe and Unsubscribe methods
{
[OperationContract]
void DuplexMessageTest(string text);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class FinanceService : IFinanceService
{
// Subscription boilerplate code
private static readonly
DuplexServiceSubscriptionManager<IFinanceServiceCallback> _subscriptionManager = new DuplexServiceSubscriptionManager<IFinanceServiceCallback>();
public bool Subscribe()
{
return _subscriptionManager.Subscribe();
}
public bool Unsubscribe()
{
return _subscriptionManager.Unsubscribe();
}
// A test method for simulation
public void DuplexMessageTest(string text)
{
_subscriptionManager.InvokeCallbackMethod(callback => callback.OnDuplexTest(text));
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single, AutomaticSessionShutdown=true)]
public class FinanceServiceCallbackSubscription : BaseServiceSubscription<IFinanceService>, IFinanceServiceCallback
{
public FinanceServiceCallbackSubscription() : base()
{
}
public delegate void DuplexTestEventHandler(string message);
public event DuplexTestEventHandler DuplexTest;
public void OnDuplexTest(string message)
{
-->> At this point, the Thread.CurrentPrincipal is reset <<--
if (DuplexTest != null)
DuplexTest(message);
}
}
[ServiceContract(SessionMode=SessionMode.Required,CallbackContract=typeof(IFinanceServiceCallback))]
公共接口IFinanceService:IServiceContract,ISupportCallback//callback.OnDuplexTest(text));
}
回调实现:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IFinanceServiceCallback))]
public interface IFinanceService : IServiceContract, ISupportCallback // <-- Interface that defines Subscribe and Unsubscribe methods
{
[OperationContract]
void DuplexMessageTest(string text);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class FinanceService : IFinanceService
{
// Subscription boilerplate code
private static readonly
DuplexServiceSubscriptionManager<IFinanceServiceCallback> _subscriptionManager = new DuplexServiceSubscriptionManager<IFinanceServiceCallback>();
public bool Subscribe()
{
return _subscriptionManager.Subscribe();
}
public bool Unsubscribe()
{
return _subscriptionManager.Unsubscribe();
}
// A test method for simulation
public void DuplexMessageTest(string text)
{
_subscriptionManager.InvokeCallbackMethod(callback => callback.OnDuplexTest(text));
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single, AutomaticSessionShutdown=true)]
public class FinanceServiceCallbackSubscription : BaseServiceSubscription<IFinanceService>, IFinanceServiceCallback
{
public FinanceServiceCallbackSubscription() : base()
{
}
public delegate void DuplexTestEventHandler(string message);
public event DuplexTestEventHandler DuplexTest;
public void OnDuplexTest(string message)
{
-->> At this point, the Thread.CurrentPrincipal is reset <<--
if (DuplexTest != null)
DuplexTest(message);
}
}
[CallbackBehavior(UseSynchronizationContext=false,ConcurrencyMode=ConcurrencyMode.Single,AutomaticsSessionShutdown=true)]
公共类FinanceServiceCallbackSubscription:BaseServiceSubscription,IFinanceServiceCallback
{
public FinanceServiceCallbackSubscription():base()
{
}
公共委托无效DuplexTestEventHandler(字符串消息);
公共事件双工测试;
公共无效OnDuplexTest(字符串消息)
{
-->>此时,Thread.CurrentPrincipal被重置。您的服务是如何配置的?@ErikFunkenbusch更新了服务配置问题。您的代码是在IIS、应用程序还是服务中运行的?它运行的进程的标识是什么?服务是如何创建的?哦,仅供参考,您的非活动超时没有按照您的想法执行确实如此……这是一个被广泛误解的设置,与receiveTimeout一起工作。receiveTimeout控制在中断连接之前无法接收消息的最长时间。inactivityTimeout控制发送心跳消息的时间(指定时间的一半)@ErikFunkenbusch我已经包括了创建服务的工厂方法。