我正在做一些单元测试,并在 WCF 中遇到了一个有趣的问题。我有一项使用 wsHttpBinding
的服务,配置如下:
<bindings>
<wsHttpBinding>
<binding name="wsHttpUnsecured">
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
服务的实现是:
public void DoWork()
{
OperationContext o = OperationContext.Current;
if (o == null) return;
if (o.ServiceSecurityContext.AuthorizationContext.Properties.ContainsKey("x"))
throw new ApplicationException();
o.ServiceSecurityContext.AuthorizationContext.Properties.Add("x", "x");
}
它在这里所做的只是检查操作上下文,如果 AuthorizationContext 中没有“X”,则添加一个。如果已经有一个“X”,则异常(exception)。 (这严格设置为一个简单的测试。在正常使用中,这将发生在自定义 AuthorizationManager 和 Token Authenticator 中)。
所以基本上,如果我们在同一个 operationContext 和 AuthorizationContext 中多次调用该方法,那么我们会看到一个异常。
现在,这是我的测试夹具。
[Test]
public void CallTwice()
{
using (var cli1 = new TestBusinessClient())
{
cli1.DoWork();
cli1.Close();
}
using (var cli2 = new TestBusinessClient())
{
cli2.DoWork();
cli2.Close();
}
}
因此,遍历运行时发生的事情:
TestBusinessClient
被 build 。 DoWork()
. DoWork()
在 AuthorizationContext.Properties
中找不到“X” . DoWork()
将“X”添加到 AuthorizationContext.Properties
. TestBusinessClient
被 build 。 DoWork()
. DoWork()
在上次调用的属性中找到“X”。 DoWork()
抛出异常。 所以我的问题是;为什么是
OperationContext
和 AuthorizationContext
当新客户端连接到同一服务时不会被杀死?我明白 wsHttpBinding
默认情况下在调用之间使用 session 上下文,但我认为该 session 将是每个客户端。当我连接到客户端的新实例时,我希望 WCF session 以及它的上下文全部更新。任何人有任何想法或想法?这里想要的结果是
AuthorizationContext.Properties
在两次调用之间重置 DoWork()
由两个不同的客户。更新 1
我尝试设置服务
PerCall
和 PerSession
,两者都没有区别。我还尝试了打开和关闭可靠消息传递的服务,但都没有改变任何东西。
我还在第一次调用和第二次调用时保存了我的 operationContext,并比较了两者:
OperationContext first; // context from first call to DoWork()
OperationContext second; // context from second call to DoWork()
(first == second) = false
(first.ServiceSecurityContext == second.ServiceSecurityContext) = false
(first.ServiceSecurityContext.AuthorizationContext == second.ServiceSecurityContext.AuthorizationContext) = true
所以看起来操作上下文被更改/重新创建,但某些设置相同
AuthorizationContext
在每次后续服务调用中。更新 2
这是所有服务器端的东西:
[ServiceContract]
public interface ITestBusiness
{
[OperationContract(Action = "*", ReplyAction = "*")]
string DoWork();
}
public class TestBusiness : ITestBusiness
{
public string DoWork()
{
System.ServiceModel.OperationContext o = System.ServiceModel.OperationContext.Current;
if (o != null)
{
if (o.ServiceSecurityContext.AuthorizationContext.Properties.ContainsKey("x"))
throw new ApplicationException();
else
o.ServiceSecurityContext.AuthorizationContext.Properties.Add("x", "x");
}
}
return "";
}
作为健全性检查,我执行了以下操作:
DoWork()
. TestDriven.NET
运行测试在 VS 2008 内。.dll
来自 NUnit's
独立的 GUI 工具,然后运行它。 第一次测试通过,第二次失败。所以看起来这纯粹是服务器端,因为从 2 个不同的进程运行相同的服务调用最终会得到相同的
AuthorizationContext
.我开始怀疑 WCF 内部的某些东西是否仍然停留在
WindowsAuthentication
上。并重复使用相同的 Auth
上下文,因为我使用相同的用户名登录到同一个域?我的服务设置为使用自定义 AuthorizationManager
: <serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="My.Namespace.CustomAuthMgr" />
</behavior>
哪里
My.Namespace.CustomAuthMgr
扩展 ServiceAuthorizationManager
.如果我在 CustomAuthMgr.CheckAccess()
中设置断点,然后在第一次通话时,operationContext.ServiceSecurityContext.AuthorizationContext
很清楚,在第二次通话中,它包含我在上一次通话中放入的任何内容。这是我自己的代码的第一个方法被 WCF 执行,所以在授权阶段之前的东西是重新加载我的 AuthorizationContext
.更新 3
一些补充信息:为了验证一些事情,我改变了我的服务实现,不再抛出异常,而是返回一个被调用次数的计数器,加上当前线程 ID:
public string DoWork()
{
var o = System.ServiceModel.OperationContext.Current.ServiceSecurityContext.AuthorizationContext;
if (o != null)
{
if (o.Properties.ContainsKey("x"))
o.Properties["x"] = (int)o.Properties["x"] + 1;
else
o.Properties.Add("x", 1);
}
return o.Properties["x"].ToString() + " | " + System.AppDomain.GetCurrentThreadId().ToString();
}
然后从
NUnit
运行一次测试GUI 导致:1 | 3816
然后我关闭
NUnit
GUI,重新启动它,然后再次运行测试:2 | 3816
然后我关闭
NUnit
再次 GUI,并从 TestDriven.NET
运行测试在 Visual Studio 中:3 | 3816
所以它绝对坚持我的
AuthorizationContext
客户端进程之间,但同一个线程处理每个服务调用,所以可能 AuthorizationContext
只是线程静态的还是什么?不,这与线程无关。我加了一个
Thread.Sleep(10000);
到服务实现,然后运行 2 NUnit
GUI 一次,每个 GUI 都打印出“2”但具有不同的线程 ID:2 | 5500
2 | 5764
所以
AuthorizationContext
也被跨线程持久化。漂亮。
最佳答案
这实际上取决于您如何定义 session 和客户端。如果您从同一个进程进行两次调用,则 WCF 通信层很可能会在同一连接上对它们进行多路复用。
您是否真的尝试过从完全不同的进程运行两个连接?你能达到同样的结果吗?
关于.net - 来自不同客户端的调用之间未清除 WCF AuthorizationContext。 (原为 : When does a WCF service session actually end? ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1189818/