Fortuna Entwickler Blog

Hier wird Ihnen geholfen

Xcode mit TFS verbinden

Es gibt nun ein Git-Repository auf unserem TFS:

http://tfs.gutingia.local:8080/tfs/DefaultCollection/_git/Xcode

Zuerst einmal: Die Arbeit mit einem Git-Repository ist grundlegend anders als wir das bisher mit TFS gewohnt sind. Hiermit werde ich mich noch gesondert beschäftigen.

Um nun ein Projekt in diesem Repository abzulegen, holt man sich idealerweise erst einmal das bestehende Repository. Das Ganze geht am besten über die Kommandozeile. Im Launchpad unter Andere findet man das Terminal. Hier wechselt man in das Verzeichnis, in welchem das Repository abgelegt werden soll und gibt dann ein Git-Kommando ein:

git clone http://tfs.gutingia.local:8080/tfs/DefaultCollection/_git/Xcode

Damit holt man sich den aktuellen Inhalt aus dem Repository.

Anschliessend kann man Xcode starten und wenn man ein neues Projekt anlegt, wählt man den Ordner "Xcode" aus, welcher durch den Git-Befehl oben erstellt wurde. Fertig.

Mac einrichten und ins Firmennetzwerk einbinden

Um einen Mac in ein Windowsnetzwerk einzubinden muss man einige, wenige Einstellungen vornehmen. Bei der Erstinstallation muss man auf jeden Fall einen lokalen Benutzer anlegen, der dann auch lokaler Admin ist. Mit diesem Account kann man dann lokal alles einstellen; ich habe den lokalen Benutzer myLife genannt; das Passwort dazu ist der Administration (Sascha/Erico) bekannt.

Zentraler Anlaufpunkt für alle Änderungen sind die Systemeinstellungen, die man unten im Dock findet:

Zuerst einmal sollte man sicherstellen, daß man sich im Firmennetzwerk befindet. Also entweder ist der Mac per Netzwerkkabel angeschlossen, oder im mylifeLAN angemeldet. Das Passwort für dieses WLAN ist der Administration bekannt.

Im ersten Schritt gibt man dem Mac einen im Netzwerk eindeutigen Namen. Dies sollte in Absprache mit Sascha/Erico geschehen. Den Anfang gemacht haben die Namen MacBook01 und MacMini01. Den Namen vergibt man in den Systemeinstellungen unter Freigaben.
Laut einigen Seiten im Internet kann es sein, daß man sich nach einem Wechsel des Namens einmalig Ab- und wieder Anmelden oder besser noch, den Mac neu starten sollte.

Als nächstes sollte man den Proxy eintragen, damit man schon einmal Verbindung 'nach draußen' hat. Dies geschieht in den Systemeinstellungen unter Netzwerk. Dort unter Weitere Optionen und dann unter Proxies.

Die eigentliche Anmeldung im Netzwerk geschieht dann unter Benutzer & Gruppen in den Systemeinstellungen. Hier muss man das Bearbeiten der Einstellungen erst einmal über das Schloss unten (und Eingabe des Passworts) freigeben.
Dann klickt man auf Anmeldeoptionen und dort dann auch Netzwerk-Account-Server Verbinden...
Dort gibt man dann den Namen des Domain Controllers/AD-Servers an und wird dann nach Benutzername und Kennwort gefragt. Hier ist ein Benutzer anzugeben, welcher Administrationsrechte im Netzwerk hat. Nach klick auf OK sollte sich der Mac im Netzwerk einbinden.
Es kann unter umständen Probleme geben bzw. die Anmeldung funktioniert nicht, wenn es zwischen dem AD-Server und dem Mac einen Zeitunterschied von 5 Minuten oder mehr gibt. Dies liegt laut einer Webseite in der Verschlüsselung der Übertragung begründet. Wenn also etwas nicht klappt, sollte man das als Erstes mal prüfen.

Zurück in den Anmeldeoptionen sollte man oben noch die Option Name und Kennwort wählen; Liste der Benutzer ist in einem Netzwerk nicht sinnvoll.

Ich habe zudem die Option Menü für schnellen Benutzerwechsel abgewählt.

Das war es dann auch schon. Gegebenenfalls nach einem Neustart kann man sich mit Benutzername/Kennwort aus dem Netzwerk an selbigem anmelden.

RESTful Service erstellen und Konsumieren mit RestSharp

Ich habe mich im Rahmen der Restschuldversicherung für die von Essen Bank mal mit RESTful Services beschäftigt, da ich eine ganze Reihe an Daten an den Service übergeben muss und auch viele Daten zurückbekomme, liegt der Fokus erst einmal auf POST.

Das Ganze wollte ich erst einmal einfach halten, um bei etwaigen Fehlern nicht in Unmengen von Code zu suchen. Also habe ich erst einmal mit einem ganz kleinen Service begonnen.

In Visual Studio habe ich ein neues Projekt erstellt: Installed -> Visual C# -> WCF -> WCF Service Application. Im neuen Projekt bekommt man dann ein Interface und einen Service vorgegeben, die man nach eigenem Gusto benennen kann. In meinem Fall war dies hinsichtlich des eigentlichen Ziels Fortuna.RSV.Services

Im Interface (Fortuna.RSV.Services.IRSVCalc.cs) habe ich dann erst mal einen ganz einfachen Service angelegt:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen")]
        int Berechnen(int i);

Der zugehörige Code (Fortuna.RSV.Services.RSVCalc.svc.cs) im Service selbst ist dazu denkbar einfach:

        public int Berechnen(int i)
        {
            return i * 2;
        }

In der Web.config ist der Service zudem noch einzutragen:

  <system.serviceModel>
    <services>
      <service name="Fortuna.RSV.Services.RSVCalc" behaviorConfiguration="serviceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="Fortuna.RSV.Services.IRSVCalc" behaviorConfiguration="web"></endpoint>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>

Damit ist der Service auch schon fertig und grundsätzlich einsatzbereit. Man kann ihn schon im Visual Studio testen.

Nun wollte ich natürlich auch mal sehen, wie man den Service konsumieren kann. Natürlich geht das, indem man einen Request an den Service schickt und die Response auswertet. Anstatt alles 'von Hand' zu machen, habe ich mich entschieden, RestSharp zu verwenden. Informationen dazu findet man auf RestSharp.org und man kann das Package über nuget in sein Projekt einbinden.

Um das nun zu testen habe ich ein neues Projekt (einfach eine C# ClassLibrary) hinzugefügt und über nuget RestSharp in den Referenzen ergänzt. Das Projekt habe ich Fortuna.RSV.ServiceClient genannt, aus class1.cs wurde RSVService.cs:

    public class RSVService
    {
        private string _ServiceBaseUri;
        public RSVService()
        {
        }
        public RSVService(string Uri)
        {
            _ServiceBaseUri = Uri + "RSVCalc.svc/";
        }
        public int Berechnen(int Eingabe)
        {
            int Ausgabe = 0;
            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(Eingabe);
            var response = client.Execute(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = int.Parse(response.Content);
            return Ausgabe;
        }
    }

Was passiert hier in der Methode Berechnen?

Es wird ein RestClient erstellt; dies ist ein Objekt, welches von RestSharp zur Verfügung gestellt wird. Als Parameter wird die Uri des Service angegeben. Selbige wird im Konstruktor meiner Klasse übergeben. Anschliessend wird der RestRequest definiert. Auch dies ist ein Objekt von RestSharp. Hier geben wir schon an, wie die Methode heisst, die aufgerufen wird, in unserem Fall 'Berechnen', was dem Wert entspricht, der oben als 'UriTemplate' im Contract steht. Als Methode habe ich auch hier (wie im Contract) POST definiert. Ebenso analog zum Contract verwende ich JSON als Datenformat.

Der Parameter (int i) wird dem RequestBody hinzugefügt; RestSharp kümmert sich um die Serialisierung in JSON, was in diesem Fall denkbar wenig ist, aber für die eigentliche Zielsetzung durchaus von Belang ist.

Anschliessend wird der Request mit Execute ausgeführt und das Ergebnis (die Response) in einer Variablen abgelegt. Das Ergebnis des Service erhält man bei dieser Art des Aufrufs in der RestResponse-Property 'Content'. Fertig.

Hier würde natürlich erst mal alles ganz einfach gehalten: Ein integer wird übergeben und ein integer wird zurückgeliefert. Im nächsten Schritt wollte ich dann ein einfaches Objekt mit zwei integer-Werten liefern und einen integer zurückbekommen. Im Service-Interface sieht das dann so aus:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen3")]
        int Berechnen3(BerechnenClass data);

Die Berechnen Class ist denkbar übersichtlich:

    [DataContract(Namespace="http://fortuna.mylife-leben.de/RSV")]
    public class BerechnenClass
    {
        [DataMember]
        public int parm1 { get; set; }
        [DataMember]
        public int parm2 { get; set; }
    }

Und auch den Code des Service habe ich einfach gehalten:

        public int Berechnen3(BerechnenClass data)
        {
            return data.parm1 * data.parm2;
        }

In der Web.config ist jetzt nichts weiter einzutragen; der Service ist dort ja bereits vorhanden; es kommt nur eine neue Methode dazu.

Im Client benötige ich natürlich auch das Objekt und der Code ist in grossen Teilen mit dem ersten identisch:

        public int Berechnen3(int parm1, int parm2)
        {
            BerechnenClass c = new BerechnenClass() { parm1 = parm1, parm2 = parm2 };
            int Ausgabe = 0;
            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen3", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(c);
            var response = client.Execute(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = int.Parse(response.Content);
            return Ausgabe;
        }

Auch hier wieder: Client erstellen, Request erstellen, dann aber eben das zu übergebende Objekt dem RequestBody hinzufügen, die Serialisierung nach JSON wird von RestSharp übernommen, dann der Aufruf des Services und die Verarbeitung der Response. Fertig.

Nachdem auch dies funktioniert wollte ich nun das Objekt übergeben, welches zur Berechnung und als Ergebnis bei der Restschuldversicherung bereits vorhanden ist. Ein Klasse mit deutlich über 30 Parametern, sowohl integer als auch double Werte, also schon etwas größer als das, was ich hier bisher verwendet habe. Die Klasse heisst 'RSVdaten'

Das Interface ist ähnlich wie gehabt:

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "Berechnen2")]
        RSVdaten Berechnen2(RSVdaten data);

Der Code im Service ist sehr einfach, weil die eigentliche Berechnung in C++ abgebildet ist:

        public RSVdaten Berechnen2(RSVdaten data)
        {
            RSVInterfaceUnmanaged.ClassRSVBer myClass = new ClassRSVBer();
            myClass.ber(data);
            return data;
        }

Während dies alles nicht weiter aufregend ist, gab es jetzt für den Client eine gewisse Herausforderung. Bisher haben die Methoden int zurückgeliefert, hier jetzt aber ein komplexes Objekt. RestSharp bietet hier eine schöne Variante des 'Execute' an:

        public RSVdaten Berechnen2(RSVdaten data)
        {
            RSVdaten Ausgabe = new RSVdaten();

            var client = new RestClient(_ServiceBaseUri);
            var request = new RestRequest("Berechnen2", Method.POST);
            request.RequestFormat = DataFormat.Json;
            request.AddBody(data);

            var response = client.Execute<RSVdaten>(request);
            if (response.ResponseStatus == ResponseStatus.Completed)
                Ausgabe = response.Data;

            return Ausgabe;
        }

Beim Execute gibt man bereits an, von welchem Typ man die Response erwartet. Den Inhalt findet man dann nciht im Parameter Content, sondern in Data, welcher dann schon vom angegeben Typ ist. Mehr ist auch hier nicht zu tun.