Kompilieren mit csc

Je nachdem welche .NET Frameworks auf dem Rechner installiert sind, lässt sich das Programm csc.exe auf anderen Pfaden finden. Zum Beispiel weist ein Server der das .NET Framework 1, 2, 3 und 3.5 installiert hat folgende Ordner auf:

Jedes Verzeichnis beinhaltet seine eigene csc.exe.

Erstellen einer exe

Um eine exe-Datei zu erstellen, ist lediglich anzugeben, welche cs-Dateien in eine exe-Datei gepackt werden sollen bzw. auf welche dll-Dateien sie sich beziehen.

csc /r:<Reference>.dll /out:<Target>.exe *.cs

Beispiel:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /r:bin\TurnoverTool.dll /out:bin\ReportingEmail.exe scheduler_tasks\ReportingEmail.cs

Erstellen einer dll

Um eine dll-Datei zu erstellen, können wie oben beschrieben wieder eine oder mehrere Referenzen zu anderen dlls und die Dateien, die in diese Library gepackt werden sollen, angegeben werden. Braucht man die dll-Datei für Webpages, so sollte die dll anschließend im bin Verzeichnis der Webpage liegen.

csc /target:library /r:<Reference1>.dll [/r:<Reference2>.dll ...] /out:<Target>.dll *.cs

Beispiele:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /target:library /out:bin\HtmlUtilities.dll src\HtmlUtilities\*.cs

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /target:library /out:bin\TurnoverTool.dll /r:bin\HtmlUtilities.dll src\TurnoverTool\*.cs

Um die dll-Datei im GAC (Global Assembly Cache) zu installieren, muss sie mit einem starken Namen verschlüsselt werden. Hierfür ist zunächst eine Key-Datei zu erstellen. Dies wird mit dem Programm sn.exe erreicht, das sich im Installations-Pfad der Visual Studio Installation oder von Windows-SDKs befindet.

Beispiele:
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sn.exe
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin

Um eine Key-Pair-Datei zu erstellen ist folgender Aufruf notwendig:

sn -k <target file>

Beispiel:
"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sn.exe" -k test.snk

Anschließend ist die dll - Datei entsprechend signieren. Hierfür ist für den Befehl csc die Option /keyfile:<keyfile> zu verwenden.

Beispiel:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /target:library /out:bin\HtmlUtilities.dll /keyfile:key.snk src\HtmlUtilities\*.cs

Um die Datei im GAC zu installieren, ist das Verzeichnis C:\WINDOWS\assembly zu öffnen und von einem anderen Explorer-Fenster die dll-Datei hinzuziehen.

Aufruf von Webservices mit C#

Es ist eine ähnliche Vorgangsweise wie bei Java zu wählen, allerdings gibt es einige Fallen, die zu umgehen sind.

Generieren einer Proxy-Klasse

Mit dem Tool wsdl.exe kann von einem Webservice ein Proxy-Klasse erstellt werden, die verwendet wird, um mit dem Webservice zu kommunizieren. Dabei ist zu beachten, dass man die WSDL-Definition, die im XML-Format vorliegt, zunächst lokal speichert ansonsten kann es zu folgendem Fehler kommen:

Error: There was an error processing 'http://www.myserver.com/Webservice.asmx?wsdl'.
- The HTML document does not contain Web service discovery information.


Man ruft daher im Browser die ASMX-Datei auf und fügt noch ?wsdl an. Danach wird der XML-Inhalt angezeigt. Man kann ihn aber nicht kopieren, da - Zeichen enthalten sind, um die Darstellung zu verkürzen. Daher muss man den Quelltext anzeigen lassen und diesen lokal abspeichern.

Danach kann man mittels wsdl.exe die Proxy-Klasse erstellen. Der Aufruf lautet wie folgt:

"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\wsdl" /l:CSharp Webservice.wsdl

Dabei repräsentiert /l:CSharp die Programmiersprache, in welcher der Proxy-Code erstellt werden soll und Webservice.wsdl die abgespeicherte XML-Datei. Alternativ kann man mit /n:<Namespace> auch einen Namespace für den Proxy-Code vergeben.

Ältere .NET Versionen
Für Applikationen, die auf .NET Version 1 basieren, muss allerdings darauf geachtet werden, dass eine Proxy-Klasse generiert wird, die zu .NET Version 1 kompatibel ist. Daher muss man eine ältere Version der wsdl.exe verwenden. Der Aufruf ändert sich demnach zu:

"C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\wsdl" /l:CSharp Webservice.wsdl

XML-Schemas
Folgender Fehler tritt auf, wenn aus der wsdl-Datei XML-Schemas importiert werden (<xsd:import namespace="..." schemaLocation="..."/>):

Fehler: Die Bindung 'IMyInterface' aus dem Namespace 'urn:com.mylibrary.something'
kann nicht importiert werden.
- Der Vorgang 'MyMethod' kann nicht importiert werden.
- Das Element 'urn:com.mylibrary.something:MyMethod' ist nicht vorhanden.


In diesem Fall sind die Schemas lokal als xsd-Dateien zu speichern und dann beim wsdl-Aufruf nach der wsdl-Datei anzuführen. Beispiel:

"C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\wsdl" /l:CSharp Webservice.wsdl MyImportedSchema.xsd

Aufruf des Webservices

Anschließend kann die Proxy-Klasse in ein C#-Projekt eingebunden werden. Im folgenden wird eine einfache C#-Konsolenapplikation besprochen.

Um das Webservice aufzurufen ist beispielsweise folgender Code nötig:

        using System;

        public class WebserviceCall {

          public static void Main(string[] args) {
            RunWf pRunWf = new RunWf();

            pRunWf.PreAuthenticate = true;
            pRunWf.Credentials = System.Net.CredentialCache.DefaultCredentials;


            bool bStarted = pRunWf.StartWf();
            Console.WriteLine(bStarted);
          }
        }
      

Dabei wird einfach ein Objekt der Proxy-Klasse RunWf instanziert und danach die entsprechende Methode StartWf() ausgeführt. Wichtig ist allerdings, dass auf das Proxy-Objekt, welche für das Programm das Service repräsentiert, folgende Methoden ausgeführt werden:

        .PreAuthenticate = true;
        .Credentials = System.Net.CredentialCache.DefaultCredentials;
      

Dies ist notwendig, um den Fehler The request failed with HTTP status 401: Unauthorized. zu vermeiden.

Zusätzlich wurde in der web.config des virtuellen Directories, in der sich die ASMX-Datei (= das Webservice) befindet, folgende Einstellung ergänzt:

        <system.web>
          <webServices>
            <protocols>
              <add name="HttpGet" />
              <add name="HttpPost" />
              <add name="HttpSoap" />
            </protocols>
          </webServices>
        </system.web>
      

Diese Ergänzung soll es ermöglichen, dass HTTP-Get, HTTP-Post und SOAP-Zugriffe auf das Webservice erlaubt werden. (Mit remove kann man dies explizit verbieten.)

Um den Proxy und obigen C#-Code in eine Exe-Datei zu kompilieren, kann man folgenden Aufruf ausführen:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc *.cs

Konfigurationsdateien

Applikation (exe)

Wird eine Applikation erstellt mit dem Namen Text.exe, so muss die Konfigurationsdatei Text.exe.config benannt werden und im Verzeichnis der exe-Datei liegen. Sie kann beispielsweise folgendes Aussehen haben:

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <appSettings>
          <add key="Setting1" value="Value1" />
          <add key="Setting2" value="Value2" />
        </appSettings>

        <connectionStrings>
          <add name="Database" providerName="System.Data.SqlClient"
            connectionString="<ConnectionString>" />
        </connectionStrings>
      </configuration>
      

Aus der C#-Applikation kann der Connectionstring wie folgt abgerufen werden:

        m_pConnectionString =
        (string)System.Configuration.ConfigurationManager.ConnectionStrings["Database"];
      

ASP.NET Anwendungen

Hier funktioniert es analog, allerdings wird die Konfiguration immer in der web.config gehalten und muss im Verzeichnis der aspx-Dateien liegen.

App-Setting Parameter

Werden Parameter im Abschnitt appSettings eingefügt, so können diese wie folgt im C#-Code abgerufen werden:

      string pValue1 =
      (string)System.Configuration.ConfigurationManager.AppSettings.Get("Setting1");
      

Byte Array in String umwandeln

Ich hatte zuletzt die Aufgabe einen Unicode codierten Text auszulesen, der in einer SQL Server Datenbank als Datentyp image abgespeichert war. D.h. wenn man ein Select auf diesen Wert absetzt, dann erscheint beispielsweise folgender Inhalt:

0x7B005C0072007400660031005C0061006E00730069005C0061006...

Ich habe zunächst nach eine Lösung im Internet gesucht, bevor ich den Byte Array selbst bearbeitet hätte. (Ich hatte nämlich schon die Idee, in einer Schleife jeweils 4 Zeichen des Byte Arrays in einen Buchstaben umzuwandeln.) Und wie so oft bin ich bei StackOverflow fündig geworden.

Somit habe ich folgende Lösung erarbeiten können:

      try {
        byte[] pByteArray = (byte[])pResultRow["<Fieldname>"];
        string pString = System.Text.Encoding.Unicode.GetString(pByteArray);
      }
      catch (Exception) {}
      

Dabei ist pResultRow ein Objekt vom Typ DataRow, das vom DataTable Objekt der Datenbankabfrage abgerufen werden kann. Davon wird der entsprechende Feldinhalt in einen Byte Array konvertiert. Danach kommt die Funktion System.Text.Encoding.<Codierung>.GetString() ins Spiel, um den Byte Array in einen String umzuwandeln. Als Codierung stellt C# Unicode, UTF32, UTF8 und UTF7 zur Verfügung.

Abruf von GET und POST Variablen

Auf folgender StackOverflow Seite gibt es zu diesem Thema eine sehr gute Antwort.

Get Variablen rufe ich in meinen Programmen immer so ab:

        string pValue1 = Request.QueryString["Value1"];
      

Post Variablen rufe ich in meinen Programmen immer so ab:

        string pValue1 = Request.Form["Value1"];
      

Oft verwende ich diesen Abruf in Kombination mit einer Methode, die bereits die Werte etwas bearbeitet. Diese speichere ich dann einer Utilities-Klasse ab:

      public static string PrepareString(string pString) {
        if (pString == null) return null;
        return pString.Trim();
      }
      

Da die Parameter als Collections abgespeichert sind kann man alle Parameter mit folgender Schleife für Get Variablen durchlaufen:

      foreach (string pKey in Request.QueryString.Keys) {
        string pValue = Utilities.PrepareString(Request.QueryString[pKey]);
      }
      

Bzw. für Post Variablen:

      foreach (string pKey in Request.Form.Keys) {
        string pValue = Utilities.PrepareString(Request.QueryString[pKey]);
      }