Biggle's Blog

Web- und Software Development

by Mario Binder

WCF Service mit Userauthentifizierung

Folgende Herangehensweise soll zeigen, wie man einen WCF Service mit Userauthentifizierung implementiert.

Zertifikat:

Um ein Zertifikat zu erstellen, kann man das Tool Pluralsight Self-Cert Tool (Mirror) dazu verwenden. In diesem Tool (als Administrator ausführen) definiert man den Namen des Zertifikates sowie den Speicherort.

Service:

Im Service erstellen wir eine Validator-Klasse die von UserNamePasswordValidator erbt. Dort überschreibt man die Methode Validate, in der man den Usernamen und die Passwortübergabe durch den Client überprüft.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyCustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }
 
        if (!(userName == "test1" && password == "test1"))
        {
            throw new SecurityTokenException("Unknown Username or Password");
        }
    }
}

app.config:

In der app.config müssen nun die Parameter konfiguriert werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 
  <system.web>
    <compilation debug="true" />
  </system.web>
 
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
 
    <services>
      <service name="SSOClientAuthentifizierungsService.Service1" behaviorConfiguration="Service1Behavior">
 
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
 
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8732/Design_Time_Addresses/SSOClientAuthentifizierungsService/Service1/" />
          </baseAddresses>
        </host>
 
        <endpoint address ="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="SSOClientAuthentifizierungsService.IService1" />
 
      </service>
    </services>
 
    <behaviors>
      <serviceBehaviors>
        <behavior name="Service1Behavior">
 
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
 
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="SSOClientAuthentifizierungsService.MyCustomUserNameValidator, SSOClientAuthentifizierungsService"/>
 
            <clientCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" />
            </clientCertificate>
 
            <serviceCertificate findValue="ssoTool" storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName"/>
          </serviceCredentials>
 
        </behavior>
      </serviceBehaviors>
    </behaviors>
 
  </system.serviceModel>
</configuration>

Client:

Der Client referenziert nun den Service und ruft über die ClientCredentials die ServiceMethoden auf:

1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
{
    Service1Client c = new Service1Client();
    c.ClientCredentials.UserName.UserName = "test1";
    c.ClientCredentials.UserName.Password = "test1";
 
    var value = c.GetData(10);
    Console.WriteLine(value.ToString());
 
    Console.ReadKey();
}

Quellen:

Downloads:

Service | Client

Viel Spaß beim entwickeln : )

by Mario Binder

WSDL wird in Chome nicht angezeigt | WCF Quicky

Wer schon einmal versucht hat, eine *.wsdl mit Chrome zu öffnen, muss feststellen das diese nicht angezeigt wird. Man hat lediglich eine leere weiße Seite vor sich.

Abhilfe schafft hier die Quellcode-Ansicht von Chrome ; )

by Mario Binder

Enumeration im WCF Service

Ich stellte mir heute die Frage, müssen in einem WCF Service die einzelnen Werte einer Enumeration mit dem Attribute [DataMember] versehen werden? Jein.

Nicht durch [DataMember] sondern durch [EnumMember] werden alle Werte in der Aufzählung bekannt gemacht.

[DataContract]
public enum MyEnum
{
    [EnumMember]
    Enum1,
 
    [EnumMember]
    Enum2
}

Die Antwort lieferte schnell die MSDN

Viel Spass beim entwicklen : )

by Mario Binder

WCF Service Test – Selfhosting

Will man einen WCFService z.B. in eine Umgebung wie CruiseControl ablegen, um diesen automatisiert zu testen, muss er dafür sorgen das der WCFService auch zur Verfügung steht. Es liegt hier also nahe, das der Test den WCFService selbständig hostet.

Um einen WCF Service selbst zu hosten, bedarf es einige kleine Vorbereitungen.

1.) Der Test muss den WCFService sowohl als Servicehost als auch als Client bereitstellen.

2.) Im TestFixtureSetup muss der Host dann entsprechend geöffnet und im TestFixtureTearDown wieder geschlossen werden.

Das Testprojekt referenziert als Konsument den WCFService über die ServiceReferenz.

Die dafür angelegte App.conf muss um einen ServiceHost Knoten erweitert werden. Im nachfolgenden kann dieser wie folgt aussehen:

1
2
3
4
<service name="MyWCFService">
  <endpoint address="http://localhost:8731/Design_Time_Addresses/Services/MyWCFService/"
              binding="basicHttpBinding" bindingConfiguration="" contract="MyWCFService" />
</service>

Der Client Knoten in der app.conf bleibt so, wie er automatisch angelegt wurde.

Um Sicherzustellen das der Test den WCFService selbständig hochfahren kann, muss dieser den WCFService auch über die DLL referenzieren.

Nun muss in der Testklasse der Host geöffnet und auch wieder geschlossen werden. Hier bietet sich die TestFixtureSetUp und die TestFixtureTearDown Methode an.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
System.ServiceModel.ServiceHost _host;
 
[TestFixtureSetUp]
public void TestFixtureSetup()
{
    Trace.WriteLine(">> Test-Start");
 
    //host oeffnen
    _host = new ServiceHost(typeof(Namespace.Pfad.zum.WCFService));
    _host.Open();
}
 
[TestFixtureTearDown]
public void TestTearDown()
{
    //host schliessen
    try { _host.Close(); }
    finally
    {
        ((IDisposable)_host).Dispose();
    }
    Trace.WriteLine(">> Test-Ende");
}

Wird der Test nun hochgefahren, hostet der Test quasi den WCFService selbst und kann diesen somit  testen.

Viel Spass beim entwickeln : )

by Mario Binder

WCFService testen

Um einen WCFService zu testen, muss man diesen sowohl als Client als auch als Host bereitstellen. Um den WCFService auch als Host bereitzustellen ergänzt man im TestProjekt die app.config innerhalb <system.servicemodel> um folgendes Element

1
2
3
4
5
6
<services>
	<service name="MyDataService">
		<endpoint address="http://localhost:8731/Design_Time_Addresses/MyDataService/MyDataService/"
            binding="wsHttpBinding" bindingConfiguration="" contract="MyDataService.Contract.IMyDataService" />
	</service>
</services>

Im TestFixtureSetUp der Testklasse, muss der ServiceHost dann geöffnet werden.

1
2
_host = new ServiceHost(typeof(MyDataService));
_host.Open();

_host ist eine Instanz von ServiceHost aus System.ServiceModel

Im TestFixtureTearDown sollte dieser dann auch wieder geschlossen werden

1
2
3
4
5
try { _host.Close(); }
finally
{
    ((IDisposable)_host).Dispose();
}

“MyDataService” natürlich anpassen ; )

by Mario Binder

Der Typname “” ist im Typ “” nicht vorhanden

Wenn man seinem Projekt eine ServiceReference hinzufügt und die Fehlermeldung Der Typname “xxx” ist im Typ “xxx” nicht vorhanden bekommt, der sollte einfach mal den Namespace überprüfen ; )