ich einige Unit-Tests zu tun, und lief in ein interessantes Problem in WCF. Ich habe einen Dienst die wsHttpBinding
verwenden, konfiguriert als solche:WCF AuthorizationContext wurde zwischen Anrufen von verschiedenen Clients nicht gelöscht. (War: Wann ist eine WCF-Dienst-Sitzung tatsächlich am Ende?)
<bindings>
<wsHttpBinding>
<binding name="wsHttpUnsecured">
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
Die Implementierung des Dienstes ist:
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");
}
Alles, was es hier tut, ist die Operation Kontext überprüft, und wenn es nicht ist "X" im AuthorizationContext, dann fügen Sie einen hinzu. Wenn es bereits ein "X" gab, dann Ausnahme. (Dies ist streng als ein einfacher Test eingerichtet. Im normalen Gebrauch würde dies in einem benutzerdefinierten AuthorizationManager und Token Authenticator passieren).
Also, im Grunde, wenn wir die Methode mehr als einmal innerhalb der gleichen OperationContext und AuthorizationContext aufrufen, dann werden wir eine Ausnahme sehen.
Jetzt ist hier meine Testvorrichtung.
[Test]
public void CallTwice()
{
using (var cli1 = new TestBusinessClient())
{
cli1.DoWork();
cli1.Close();
}
using (var cli2 = new TestBusinessClient())
{
cli2.DoWork();
cli2.Close();
}
}
So zu Fuß durch, was zur Laufzeit passiert:
- Ein neues
TestBusinessClient
erstellt wird. - Es macht einen Aufruf an
DoWork()
. DoWork()
findet nicht "X" inAuthorizationContext.Properties
.DoWork()
fügt "X" zuAuthorizationContext.Properties
hinzu.- Die Testmethode verfügt über den ersten Client.
- Ein neues zweiten
TestBusinessClient
erstellt. - Es macht einen Aufruf an
DoWork()
. DoWork()
findet "X" immer noch in den Eigenschaften des letzten Anrufs.DoWork()
löst eine Ausnahme.
Also meine Frage ist; Warum werden OperationContext
und AuthorizationContext
nicht deaktiviert, wenn ein neuer Client eine Verbindung mit demselben Dienst herstellt? Ich verstehe, dass wsHttpBinding
standardmäßig einen Sitzungskontext zwischen den Anrufen verwendet, aber ich würde denken, dass Sitzung pro Client wäre. Ich habe erwartet, dass die WCF-Sitzung und damit ihre Kontexte alle erneuert werden, wenn ich mich mit einer neuen Instanz eines Clients verbinde.
Wer noch keine Gedanken oder Ideen? Das gewünschte Ergebnis ist hier, dass AuthorizationContext.Properties
zwischen den zwei Aufrufen von den zwei getrennten Clients zu DoWork()
zurückgesetzt wird.
aktualisieren 1
Ich habe versucht, den Dienst PerCall
und PerSession
Einstellung, und weder einen Unterschied gemacht.
Ich habe auch den Dienst mit zuverlässigen Messaging ein- und ausgeschaltet, und nichts geändert.
Ich sparte auch meine Operation beim ersten Anruf und den zweiten Anruf aus und verglichen die beiden:
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
es also eine Art, wie die Operation Kontext aussieht wird/neu geändert, aber etwas setzt die Gleiches AuthorizationContext
bei jedem folgenden Service-Anruf.
Update 2
Hier ist alles, das serverseitige Material:
[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 "";
}
Als Plausibilitätsprüfung, ich habe folgendes:
- Starten einer Instanz des WCF-Servers (mit Cassini/integriertem VS 2008-Server).
- Reduzieren Sie die Testvorrichtung auf nur 1 Anruf an
DoWork()
. - Führen Sie den Test von
TestDriven.NET
innerhalb VS 2008 - Öffnen Sie den gleichen Test
.dll
vonNUnit's
Standalone-GUI-Tool, und es laufen.
Der erste Testlauf läuft, und der zweite schlägt fehl. Es scheint also, dass dies rein serverseitig ist, da das Ausführen desselben Serviceanrufs von zwei verschiedenen Prozessen mit demselben AuthorizationContext
endet.
Ich beginne mich zu fragen, ob vielleicht etwas internes zu WCF immer noch auf WindowsAuthentication
stecken und das gleiche Auth
Kontext verwenden, da ich in der gleichen Domäne mit dem gleichen Benutzernamen angemeldet bin? Mein Service wird eine benutzerdefinierte AuthorizationManager
verwenden: ServiceAuthorizationManager
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="My.Namespace.CustomAuthMgr" />
</behavior>
Wo My.Namespace.CustomAuthMgr
erstreckt. Wenn ich einen Haltepunkt in CustomAuthMgr.CheckAccess()
einstelle, dann ist beim ersten Anruf operationContext.ServiceSecurityContext.AuthorizationContext
gelöscht, und beim zweiten Anruf ist alles enthalten, was ich vom vorherigen Anruf eingegeben habe. Dies ist die erste Methode meines eigenen Codes, die von WCF ausgeführt wird, also etwas vor der Autorisierungsphase lädt meine AuthorizationContext
.
Update 3
Einige hinzugefügt Info: Um einige Dinge zu überprüfen, ich meine Service-Implementierung ändert sich nicht mehr, eine Ausnahme zu werfen und stattdessen einen Zähler der Anzahl der Male zurückkehren genannt, plus die aktuelle Thread-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();
}
Dann läuft der Test einmal von NUnit
GUI ergibt:
1 | 3816
ich dann schließen Sie die NUnit
GUI, starten Sie ihn neu, und führen Sie den Test erneut:
2 | 3816
ich die NUnit
GUI dann wieder schließen und den Test von TestDriven.NET
in Visual Studio ausführen:
3 | 3816
so persistierenden sein meine AuthorizationContext
zwischen Client definitiv Prozessen, aber der gleiche Thread behandelt jeden Service-Aufruf, vielleicht AuthorizationContext
ist gerade Thema statisch oder so etwas?
Nein, es hat nichts mit dem Thread zu tun. Ich habe ein Thread.Sleep(10000);
an die Dienstimplementierung, lief dann 2 NUnit
GUIs auf einmal, und jeder ausgedruckt „2“, aber mit unterschiedlichem Thread-IDs:
2 | 5500
2 | 5764
So AuthorizationContext
auch über Threads beibehalten wird. Flott.
Können Sie uns den Servicevertrag (Serverseite) und die Implementierung des Dienstes zeigen (nur die Klassendefinition mit möglichen Attributen) –