Posts mit dem Label Problem werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Problem werden angezeigt. Alle Posts anzeigen

Donnerstag, 6. Mai 2010

BizTalk 2006 R2 oder nicht R2?

Wie Lösungen von trivialen Fragen in langwieriges Suchen ausarten können... "Wie ist auf die Schnelle herauszufinden ob ein BizTalk 2006 System, ein R2 Release ist?"

Es findet sich kein R2 Logo, kein Hinweis in den Add/Remove Programm Options, oder sonst etwas... WCF Adapter / RFID? Und wenn das nicht mitinstalliert wurde? Als einzigen verlässlichen Hinweis fand sich nur die Versionsnummer:

BizTalk Server 2006 Adminitration Console -> Menü "Help" -> "About Microsoft BizTalk Server Administration":

- 3.5.1602.0 = BizTalk 2006
- 3.6.1404.0 = BizTalk 2006 R2

Mal sehen wie weit das noch von diversen Patches beeinflusst wird...

Montag, 1. März 2010

BizTalk 2009, SAP Adapter 2.0 und Windows 2008 (32Bit)

Der alte (d.h. nicht WCF) Microsoft SAP Adapter unter Windows 2008 (32Bit) in Verbindung mit BizTalk 2009 kann ganz schön bockig sein...


Als erstes müssen folgende Vorraussetzungen erfüllt sein, damit der Adapter überhaupt funktioniert (unabhängig von BizTalk Version und Betriebssystem):
1. Installation der SAP eigenen DLLs, enthalten im SAP Frontend Package
2. Installation des Microsoft SAP .NET Connectors 1.0.3 (!Nicht 2.0!)
3. Installation des Microsoft BizTalk Adapter 2.0 for MySAP SP1 (unbedingt die SP 1 Version)
und das muss zudem in genau dieser Reihenfolge passieren!

Dann sollte man in einer restriktiven Umgebung unbedingt abprüfen, ob der SAP Adapter seine Datenbanktabelle und Stored Procedures angelegt hat:
1. In der Datenbank BizTalkMsgBoxDb muss eine SAPTid Table angelegt worden sein
2. Zudem müssen in der gleichen Datenbank folgende Stored Procedures existieren:
mp_sap_check_tid
mp_sap_delete_tid
mp_sap_insert_tid

sollte das nicht der Fall sein, muss mit einem geeigneten User nochmals die BizTalkSAPConfig.exe über Kommandozeile mit /i aufgerufen werden. Diese ist recht schweigsam und meldet sich nur im Fehlerfall mit einem Error Fenster.

Ist das geschehen muss sichergestellt sein, das Execution Rechte des BizTalk Users in der Datenbank auf vom SAP Adapter angelegten Stored Procedures existieren (BTS_HOST_USERS)

Ist das alles geschehen sollten zumindestens die RFC Aufrufe reibungslos passieren, sowie das Abrufen der Schemas für IDOCs und BAPI Bausteine funktionieren.


Was uns dann noch Kopfzerbrechen bereitete war, das IDOCs nicht empfangen werden konnten. Im SAP wurde unter der Transaktion SM58 ein "TARGET_METHOD_EXCEPTION raised by external server" Fehler zurückgemeldet. Unter BizTalk passierte gar nichts. Keine Fehlermeldung und keine sonstigen Einträge z.B. im Eventlog.

Nach einer Studie der Logs mit dem Process Monitor von Microsoft kam mir die Vermutung das BizTalk seine "Microsoft.BizTalk.SAPAdapterProperties.dll" nicht finden kann. D.h. er findet sie schon, allerdings sucht er sie zuerst immer im GAC_32, obwohl er seinen Adapter später im GAC findet, scheint dies trotzdem im weiteren Verlauf zu Problemen zu führen (z.B. unzählige Buffer Overflows, in den Pipeline Komponenten)

Als Problemlösung habe ich die "Microsoft.BizTalk.SAPAdapterProperties.dll" schlichtweg in den Ressourcen meines BizTalk 2009 Projekt referenziert (so wie ich es schon früher bei diesem Problem getan habe: http://justacodeblog.blogspot.com/2008/09/biztalk-und-sap-adapter-error.html). Danach funktionierte der IDOC Empfang wieder reibungslos. Ich vermute es reicht auch aus, die SAP Adapter Installation einfach vom GAC ins GAC_32 Verzeichnis manuell zu verschieben.

Nachtrag: Der Fehler TARGET_METHOD_EXCEPTION raised by external server tritt auch auf wenn das aus SAP abgerufene Schema nicht auf dem aktuellsten Stand ist.

Dienstag, 13. Januar 2009

DataBinding mit einer List<string>

Neulich stieß ich bei dem Versuch eine List<string> als Datenquelle für ein DataGridView zu verwenden auf ein interessantes Verhalten, das ich mir jedoch zunächst nicht erklären konnte.

Nehmen wir beispielsweise folgenden Code:

   1:  public FormMain()
   2:  {
   3:      this.InitializeComponent();
   4:   
   5:      List<string> tvStations = new List<string>();
   6:      tvStations.Add("Pro7");
   7:      tvStations.Add("RTL");
   8:      tvStations.Add("Sat1");
   9:      tvStations.Add("VOX");
  10:      tvStations.Add("Arte");
  11:      tvStations.Add("N24");
  12:      tvStations.Add("Phoenix");
  13:      tvStations.Add("RTL II");
  14:   
  15:      this.dgvTvStations.DataSource = tvStations;
  16:  }


Zu erwarten wäre, dass beim Start der Applikation unser DataGridView die in der Liste enthaltenen Fernsehsender anzeigt. Doch weit gefehlt, denn das Ergebnis sieht in Wirklichkeit so aus:

callingResult

Angezeigt werden uns also keineswegs die Fernsehsender sondern lediglich die Länge der Strings, die in der Liste enthalten sind.
Das liegt daran, dass die Datenquelle untersucht wird, wobei natürlich festgestellt wird, dass es sich um eine Liste von Strings handelt. Versucht man hier via Index auf einen bestimmten Wert zuzugreifen, wird man feststellen, dass die einzige verfügbare Eigenschaft dieses Wertes Length ist. Und genau diese wird dann vom DataGridView verwendet.

Um die Daten nun korrekt anzuzeigen muss ein Umweg in Kauf genommen werden.
Wir erstellen hierfür zunächst eine Klasse, die die Daten entgegennimmt, die wir anzeigen wollen. Im vorliegenden Fall könnte diese beispielsweise so aussehen:

   1:  public class TvStation
   2:  {
   3:      private string name;
   4:   
   5:      public string Name
   6:      {
   7:          get
   8:          {
   9:              return this.name;
  10:          }
  11:      }
  12:   
  13:      public TvStation(string name)
  14:      {
  15:          this.name = name;
  16:      }
  17:  }

 

Nun verwenden wir im Formular, das die Daten anzeigen soll, statt einer List<string> eine List<TvStation> und binden diese an den DataGridView.

   1:  public FormMain()
   2:  {
   3:      this.InitializeComponent();
   4:   
   5:      List<TvStation> tvStations = new List<TvStation>();
   6:      tvStations.Add(new TvStation("Pro7"));
   7:      tvStations.Add(new TvStation("RTL"));
   8:      tvStations.Add(new TvStation("Sat1"));
   9:      tvStations.Add(new TvStation("VOX"));
  10:      tvStations.Add(new TvStation("Arte"));
  11:      tvStations.Add(new TvStation("N24"));
  12:      tvStations.Add(new TvStation("Phoenix"));
  13:      tvStations.Add(new TvStation("RTL II"));
  14:      
  15:      this.dgvTvStations.DataSource = tvStations;
  16:  }

 

Wenn jetzt die Anwendung gestartet wird, zeigt der DataGridView tatsächlich die erwarteten Daten.

correctResult

Schade, dass in diesem Fall ein solcher Umweg nötig ist, aber so funktioniert DataBinding nun einfach mal.

Donnerstag, 30. Oktober 2008

Toolbox-Item hinzufügen bei installierten Power Commands nicht möglich

Gerade eben wollte ich mir die Chart Controls für das .NET Framework 3.5 anschauen, die Microsoft vor kurzem veröffentlicht hat.
Leider war nach der Installation des Pakets nichts neues im Data-Tab der Toolbox zu finden. Laut Anleitung soll man für diesen Fall die Controls einfach händisch hinzufügen. Als ich das jedoch versuchte, fror mein Visual Studio 2008 einfach ein oder stürzte gar ab. Letzteres erfreulicherweise ohne jede Fehlermeldung.

Nach ein wenig Recherche habe ich tatsächlich herausgefunden, dass das Verhalten durch die installierten Power Commands für Visual Studio 2008 hervorgerufen wird.
Also habe ich diese schnell deinstalliert und siehe da, ich kann wieder Items zur Toolbox hinzufügen.

Sehr schade, dass die Power Commands einen derart negativen Einfluss auf VS2008 haben, denn eigentlich finde ich sie sehr nützlich. Deshalb werde ich sie auch wieder installieren und hoffen, dass ich mich das nächste mal, wenn ich etwas in die Toolbox schieben möchte, daran denke, sie zuvor zu deinstallieren.

Interessant ist im Übrigen auch, dass mein Kollege die Power Commands ebenfalls installiert hat, er jedoch problemlos neue Items in die Toolbox einfügen kann...

Nachtrag:
Ich habe die Power Commands jetzt wieder installiert und erneut versucht, ein Toolboxelement hinzuzufügen. Siehe da, es funktioniert einwandfrei.

Dienstag, 22. Juli 2008

OPC: DataChange-Event

Ein OPC-Client hat die Möglichkeit, vom Server Nachrichten über Aktualisierungen von Werten zu empfangen. Das ist natürlich sehr nützlich, wenn man gerne eine bestimmte Aktion ausführen möchte, wenn ein definierter Wert erreicht wird. Kommt ja auch nicht gerade selten vor, diese Anforderung, also hat die OPC Foundation da schon ganz schön schlau definiert.

Nicht ganz so schlau ist jedoch die Umsetzung innerhalb der OpcDAAuto.dll gelungen. Ich habe heute etwa einen halben Tag gekämpft, bis ich tatsächlich in der Lage war, den DataChange-Event, der vom Server bei Veränderungen von zuvor dafür angemeldeten Werten gesendet wird, zu empfangen. Ich habe Tutorials gewälzt, das Internet durchforstet und experimentiert - alles ohne Erfolg. Alle Voraussetzungen, die ich finden konnte, schienen mir erfüllt. Nach ewigem Herumprobieren gab es nur noch einen einzigen Unterschied zwischen den Tutorials - die, heruntergeladen und kompiliert im Übrigen einwandfrei funktionierten - und meiner Applikation. Dieser fand sich beim Anlegen von OPC-Items, also jenen Werten, die ich überwachen wollte. Mein Code - im Übrigen eigentlich absolut korrekt - sah folgendermaßen aus:

   1:  OPCGroupClass opcGroupTriggerItems;
   2:   
   3:  // Gruppe anlegen
   4:  opcGroupTriggerItems = ( OPCGroupClass ) opcServer.OPCGroups.Add( "TriggerItems" );
   5:   
   6:  // Items hinzufügen
   7:  opcGroupTriggerItems.OPCItems.AddItem( connection + "/" + alias + "/TriggerItem1", 0 ) );
   8:  opcGroupTriggerItems.OPCItems.AddItem( connection + "/" + alias + "/TriggerItem2", 1 ) );
   9:  opcGroupTriggerItems.OPCItems.AddItem( connection + "/" + alias + "/TriggerItem3", 2 ) );
  10:  opcGroupTriggerItems.OPCItems.AddItem( connection + "/" + alias + "/TriggerItem4", 3 ) );
  11:   
  12:  // Event Handler Methode registrieren
  13:  // WICHTIG: Die Event Handler Methode wird erst nach dem hinzufügen der Items zur Gruppe registriert,
  14:  //          da sonst beim Hinzufügen für jedes Item ein Event ausgelöst wird.
  15:  opcGroupTriggerItems.DataChange += new DIOPCGroupEvent_DataChangeEventHandler( opcGroupTriggerItems_DataChange );

Hier wird zuerst eine Gruppe auf dem OPC-Server angelegt, zu der dann anschließend die Items hinzugefügt werden, die die Werte darstellen, die überwacht werden sollen. Um zu vermeiden, dass für alle Items ein initialer Event ausgelöst wird, der über die Änderung von "nicht vorhanden" nach "vorhanden" und die damit verbundene Wertänderung benachrichtigt, wird die Event-Handler-Methode erst nach dem Anlegen der nötigen Items registriert. So wurden die Items korrekt angelegt, sie konnten ausgelesen werden, aber die Benachrichtigung über Wertänderungen funktionierte, wie bereits erwähnt, überhaupt nicht.

Der Code, der mir von den Tutorials aufgezeigt wurde und der jetzt, nachdem ich ihn so auch in meiner Applikation habe, zu dem gewünschten Ergebnis führt, sieht so aus:

   1:  OPCGroupClass opcGroupTriggerItems;
   2:  string[] itemIds = new string[5];
   3:  int[] clientHandles = new int[5];
   4:  int[] serverHandles;
   5:  int[] errors;
   6:   
   7:  // Gruppe anlegen
   8:  opcGroupTriggerItems = ( OPCGroupClass ) opcServer.OPCGroups.Add( "TriggerItems" );
   9:   
  10:  // Items erstellen
  11:  itemIds.SetValue( connection + "/" + alias + "/TriggerItem1", 1 );
  12:  itemIds.SetValue( connection + "/" + alias + "/TriggerItem2", 2 );
  13:  itemIds.SetValue( connection + "/" + alias + "/TriggerItem3", 3 );
  14:  itemIds.SetValue( connection + "/" + alias + "/TriggerItem4", 4 );
  15:   
  16:  // ClientHandles erstellen
  17:  clientHandles.SetValue( 1, 1 );
  18:  clientHandles.SetValue( 2, 2 );
  19:  clientHandles.SetValue( 3, 3 );
  20:  clientHandles.SetValue( 4, 4 );
  21:   
  22:  // Items der Gruppe hinzufügen
  23:  opcGroupTriggerItems.OPCItems.AddItems( 4, ref itemIds, ref clientHandles, out serverHandles, out errors, null, null );
  24:   
  25:  // Event Handler Methode registrieren
  26:  // WICHTIG: Die Event Handler Methode wird erst nach dem hinzufügen der Items zur Gruppe registriert,
  27:  //          da sonst beim Hinzufügen für jedes Item ein Event ausgelöst wird.
  28:  opcGroupTriggerItems.DataChange += new DIOPCGroupEvent_DataChangeEventHandler( opcGroupTriggerItems_DataChange );

Auch hier wird zunächst eine Gruppe angelegt. Es werden hier jedoch die Items nicht, wie zuvor, einzeln der Gruppe hinzugefügt. Statt dessen werden ein String-Array mit den Werten und ein Integer-Array mit den Client-Handles, unter denen die Items eindeutig zu identifizieren sind, angelegt. Hier ist die Besonderheit zu beachten, dass der erste Wert des Arrays jeweils nicht beachtet wird, das Array wird immer nur von 1 bis max durchlaufen. Das hängt, so weit ich informiert bin, damit zusammen, dass die von mir verwendete OpcDAAuto.dll in VB geschrieben ist. Jedenfalls werden anschließend die Items und ihre Client-Handles gesamt an eine Methode übergeben, die sie der Gruppe hinzufügen. Anschließend wieder die Event-Handler-Methode registriert. Test anwerfen - funzt.  Sehr erstaunlich und für mich nicht wirklich nachvollziehbar, aber im Endeffekt ist es jetzt auch egal, es läuft ja nun :)

Montag, 9. Juni 2008

Fallstrick: DateTime.AddXXX()

Ich stolpere immer wieder darüber und wie ich heute gesehen habe, bin ich tatsächlich nicht der einzige, dem es so geht:

Auf einen vorhandenen DateTime soll eine bestimmte Anzahl von Stunden (oder Minuten, Sekunden, ...) addiert werden. Natürlich, kein Problem, dafür bietet der DateTime ja die Methode AddHours(). Ein Aufruf, um auf das aktuelle Datum mit der aktuellen Uhrzeit fünf Stunden zu addieren, sähe demnach so aus:

   1:  DateTime dt = DateTime.Now;
   2:  dt.AddHours(5.0);

Verwendet man jetzt jedoch den Wert von dt weiter, um ihn beispielsweise anzuzeigen, fällt auf, dass die fünf Stunden nicht wie erwartet auf den aktuellen Wert addiert wurden. Der Grund hierfür ist ein ganz einfacher, der einem sogar von IntelliSense angezeigt wird.
Der Aufruf geht einfach deshalb ins Leere, weil er nicht auf den übergebenen DateTime addiert, sondern das Ergebnis der Addition zurück gibt. Irgendwo logisch, es handelt sich ja nicht um einen ref- oder out-Parameter, andererseits ist es dennoch irgendwie verwirrend, da es einfach logisch erscheint, dass auf den Ursprungswert addiert wird.

Wie auch immer, der korrekte Aufruf muss wie folgt aussehen:

   1:  DateTime dt = DateTime.Now;
   2:  dt = dt.AddHours(5.0);

Auf dass ich in Zukunft nicht mehr hierüber stolpern werde!

Donnerstag, 29. Mai 2008

Seltsames Verhalten im Event Log

Zur Zeit schreibe ich, wenn es die Zeit und die Laune zulassen, an einem kleinen Tool zum Auslesen des Windows Event Log. Dabei habe ich eine recht interessante Feststellung gemacht.
Zum Auslesen der Einträge einer bestimmten Quelle, die im Event Log registriert ist, habe ich folgendes getan:

   1:  public static EventLogEntryCollection GetEntriesForSource( string logSource )
   2:  {
   3:      EventLog log;
   4:      EventLogEntryCollection entries;
   5:   
   6:      source = logSource;
   7:   
   8:      // EventLog vorbereiten
   9:      log = new EventLog();
  10:      log.Source = logSource;
  11:              
  12:      // EventLog-Einträge auslesen
  13:      entries = log.Entries;
  14:   
  15:      return entries;
  16:  }

Hier tue ich nichts anders, als ein EventLog-Objekt zu erstellen, das, wer hätte es gedacht, den Zugriff auf das Windows Event Log erlaubt.
Anschließend wird die Quelle (Source) gesetzt, deren Einträge ausgelesen werden sollen. Damit ist die Vorbereitung auch schon abgeschlossen und die Einträge innerhalb der Source können in eine EventLogEntryCollection eingelesen werden.

Damit ist das Auslesen aus der gewünschten Quelle auch schon abgeschlossen - dachte ich. Seltsamerweise werden trotz des Setzens der zu lesenden Quelle alle Einträge des Logs, in dem sich die Quelle befindet, in die EventLogEntryCollection geschrieben.

Ich möchte jetzt nicht so weit gehen zu sagen, dass es sich hierbei um einen Fehler im Konzept des Event Log-Handlings handelt, aber für mich ist es nicht logisch, alle Einträge in meine Collection geschrieben werden, obwohl ich - für meine Begriffe - eine Eingrenzung auf eine ganz bestimmte Source vorgenommen habe.

Das Schlimme daran ist nicht die Tatsache an sich, sondern viel eher, dass man sie nicht direkt wahrnimmt. Ich habe beispielsweise in eigenen Tests nie zwei mal hintereinander Quellen aus dem gleichen Log verwendet, so dass mir nie aufgefallen ist, dass alle Quellen des Logs exakt gleich viele (und vor allem die selben) Einträge hat. Das hat erst ein Betatester festgestellt (vielen Dank dafür an tropensturm!).

Die Beseitigung des Problems gestaltet sich glücklicherweise denkbar einfach, so dass in meiner Anzeige jetzt tatsächlich nur noch die erwarteten Einträge zu finden sind. Hierfür wird einfach nachträglich nochmals die Source eingegrenzt.

   1:  if( !entry.Source.Equals( source ) )

Montag, 12. Mai 2008

DataGridView - Vorderste Spalte ausblenden

Heute beschäftigen wir uns mal mit etwas, das eigentlich sehr einfach ist, mich allerdings doch etwas aufgehalten hat, weil einfach das Wissen gefehlt hat. Damit dies nicht wieder passiert, wird hier gebloggt! ;)

Die Aufgabenstellung ist eine extrem einfache:
Verwendet man ein DataGridView zur Anzeige von Daten (z.B. via DataBinding auf ein DataSet), wird standardmäßig ganz links eine Spalte angezeigt, die es ermöglicht, die komplette Zeile zu markieren und durch einen kleinen Pfeil anzeigt, dass eine Spalte die aktuelle ist.
Nun ist in meinem Fall der DataGridView so eingestellt, dass immer die ganze Zeile markiert wird, egal, wo sie angeklickt wird. Daraus folgt, dass wir die besagte erste Spalte nicht benötigen.

Naheliegend wäre es nun ja, dass diese Spalte in der Columns-Collection des DataGridView enthalten ist und sie mit dem Aufruf

   1:  myDataGridView.Columns[0].Visible = false;

unsere Anforderung erfüllt.
Startet man jetzt allerdings die Applikation, wird man feststellen, dass statt der nutzlosen Spalte ganz links die erste eigene Spalte ausgeblendet wird, die unsere Daten anzeigen sollte - so geht es also nicht!

Statt dessen bietet das DataGridView eine Eigenschaft, die festlegt, ob besagte Spalte angezeigt wird oder nicht: DataGridView.RowHeadersVisible
Die Spalte, um die es hier geht, wird also offensichtlich als RowHeader bezeichnet. Reichlich interessant, wie ich finde. Zu meiner Schande muss ich jedoch gestehen, dass ich darauf nie im Leben gekommen wäre. Zum Glück gibt es ja das Internet.

Der korrekte Aufruf zum Ausblenden der ersten Spalte sieht dann also letztendlich so aus:

   1:  myDataGridView.RowHeadersVisible = false;

Die Eigenschaft kann aber natürlich auch einfach im Eigenschaften-Fenster des Designers gesetzt werden.

Problem gelöst, ich bin glücklich und meine GUI gefällt mir wieder. Daumen hoch ;)

Mittwoch, 7. Mai 2008

Das Windows Event Log und seine Tücken

Logging ist in der professionellen Softwareentwicklung ein wichtiges Thema. Nicht umsonst gibt es eigens für das Logging eigene Frameworks wie beispielsweise das sehr gute log4net.
Dieses bietet verschiedenste Appender an, die festlegen, wie und wohin geloggt werden soll. So haben wir unter anderem die Auswahl zwischen dem Schreiben von Einträgen in Datenbanken, Textfiles, die Konsole und das Windows Event Log.
Gerade die letzte Möglichkeit bietet sich - aus meiner Sicht - besonders an, denn sie hat einen großen Vorteil: Jeder System-Administrator der Welt ist (sofern er Windows-Systeme administriert) mit dem Windows Event Log vertraut und weiß, wie er an seine Einträge heran kommt. Sicherlich, es ist auch nicht wirklich komplex, Textfiles, die an einer fest definierten Stelle im System abgelegt werden, zu analysieren, doch warum sollte man dem armen Admin zumuten, noch eine zweite Stelle zu prüfen?

Ein weiterer Vorteil des Loggens in das Windows Event Log: .NET bietet uns schon alles, was dazu nötig ist.
Die Klasse  EventLog beinhaltet tatsächlich alles, was wir brauchen und ist zudem sehr einfach zu verwenden. Nachfolgend mal ein kleiner Code-Schnipsel, der zeigt, wie man ein eigenes Log mit eigener Quelle erstellt und anschließend einen Eintrag dort hinterlegt.

   1:  using System;
   2:  using System.Diagnostics;
   3:   
   4:  namespace BBoSoft.EventLogDemo
   5:  {
   6:      public class EventLogDemo
   7:      {
   8:          [STAThread]
   9:          public static void Main()
  10:          {
  11:              // pruefen, ob die Quelle bereits existiert
  12:              if(!EventLog.SourceExists("DemoSource"))
  13:              {
  14:                  // Source anlegen
  15:                  // der erste Parameter ist die Quelle, in die geschrieben werden soll
  16:                  // der zweite Parameter ist das Log, dem die Quelle hinzugefuegt werden soll
  17:                  EventLog.CreateEventSource("DemoSource", "DemoLog");
  18:              }
  19:   
  20:              EventLog.WriteEntry("DemoSource", "DemoMessage", EventLogEntryType.Information, 150, 12);
  21:          }
  22:      }
  23:  }

Wie hier zu sehen ist, ist das Schreiben eines Eintrags in das Event Log absolut einfach zu erledigen.
Beim Aufruf von EventLog.WriteEntry() werden, für diese Überladung, fünf Parameter übergeben. Zuerst die Quelle, dann die Nachricht des Events, der Typ (Information, Warnung, Fehler), eine selbst gewählte EventId sowie eine selbst gewählte Kategorie.

Lässt man den Code so laufen und schaut in das EventLog, müsste das in etwa so aussehen:

EventLog1

Das hat also wunderbar funktioniert. Erfreulich.
Wer jetzt noch den Titel dieses Postings im Kopf hat, wird sich sicherlich fragen, wo denn hier nun die Tücken liegen. Um das zu demonstrieren, ist es nötig, zuerst einmal die erstellte Source oder am Besten gleich das gesamte Log zu entfernen. Hierzu öffnen wir den Registrierungseditor und navigieren zum Punkt HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog und löschen dort dein Eintrag DemoLog.

Zurück zum Code:
Fügen wir doch mal ein beliebiges Sonderzeichen - in meinem Fall war es ein '/' - in den Namen des Logs ein und führen sie das Programm erneut aus. Sieht das EventLog jetzt nicht richtig interessant aus? ;)

Was haben wir jetzt also gelernt?
Richtig! Sonderzeichen im Namen des Logs sind BÖSE! Ich hab es auf die harte Tour gelernt und hoffe, einigen geholfen zu haben, nicht in die gleiche Falle zu tappen.

Noch ein wichtiger Nachtrag:
Zum Anlegen der Source werden Administratorrechte für das System benötigt, da hier in die Registrierung geschrieben wird.

Dienstag, 22. April 2008

URI - Scheme erkennen?

Wie finde ich am einfachsten das URI Schema in einem String mit einer vermeidlichen URI?

Nun mein erster Gedanke ist ich komme wohl nicht herum mit einer Liste gegenzuprüfen

Der Ansatz: suche nach ":" Doppelpunkt, setzt voraus das man auch tatsächlich eine vollständige URI bekommen hat. Dies schlägt leider fehl, sobald man einen Host mit einem Port bekommt alla "localhost:80". Unweigerlich wird man wie im C# eigenem Uri Datentyp "localhost" als Schema interpretiert bekommen. Eine Erkennung ob da ein "http://" vorne fehlt, fällt aus.

Bliebe also der Ansatz, ich vergleiche das erhaltene Schema mit bekannten Schemas. Was auch nicht wirklich ideal ist.

Nun, zugegeben die Frage ufert, praktisch gesehen, unnötig aus. Meine Problemstellung war das ich aus einem System einmal Kunden Webadressen mit oder ohne "http://" bekommen kann, und dies entsprechend beim schreiben nach CRM korrigieren soll. Doch halt! Da war noch was? Genau "https://", ergo ergab sich schnell die Frage ob ich es allgemein abfragen kann...

Doch das funktioniert leider nicht da URI nur als Zeichenkette aus Buchstaben, Zahlen, -, +, . definiert ist vor einem : . Damit ist eine Verwechslung nicht ausgeschlossen mit einem Hostnamen dem eine Portdeklaration folgt!

Mein aktueller Ansatz für mein ganz eigenes spezielles Problem geht in Richtung if(!stringX.Contains(@"://")) ... damit lasse ich ganz bewußt URI Schemas wie file: oder mailto: ausfallen, da die in meinem Fall maximal unwahrscheinlich sind als Kundenadressen, es aber sehr viel wahrscheinlicher ist das ich eine unvollständige Adresse im Stile xyz.de:5000 bekomme.

Gibt es eine schönere, allgemeinere Lösung?