Frohe Weihnachten! 17.12.2010

Simone Franz
Simone Franz, Marketing Manager

Für die eXperts bzw. für die SDX war 2010 ein starkes Jahr - darauf sind wir sehr stolz!

Als Microsoft Technologie Spezialist, Innovationstreiber und Know-How-Lieferant für die IT von Großunternehmen (u.a. Commerzbank, Dekabank, Deutsche Post, Telekom, Deutsche Bahn) konnten wir von der wirtschaftlichen Erholung stark profitieren und eine hohe Auslastung erzielen.

Durch mehrere Technical Councils, Analysen (z.B. „RIA Analyse mit Silverlight“) und PoCs (z.B. WPF) konnten wir aktuellste Microsoft Technologien bei Kunden motivieren und in individuellen Softwarelösungen umsetzen.

Dieses Erfolgsmodell möchten wir auch in 2011 weiterführen, nicht nur in Frankfurt sondern dann auch an unserem neuen Standort in München.

Aber jetzt heißt es erst einmal:  2010__Frohe Weihnachten

Zum Weihnachtsfest wünschen wir Ihnen Zeit zur Ruhe, Freude und Besinnung auf das wirklich Wichtige und Schöne im Leben:

Manche Menschen wissen nicht, wie wichtig es ist, dass sie einfach da sind.
Manche Menschen wissen nicht, wie gut es tut, sie nur zu sehen.
Manche Menschen wissen nicht, wie tröstlich ihr gütiges Lächeln wirkt.
Manche Menschen wissen nicht, wie wohltuend ihre Nähe ist.
Manche Menschen wissen nicht, dass sie ein Geschenk des Himmels sind.
Aber sie wüssten es, würden wir es ihnen sagen.

Für 2011 wünschen wir Ihnen ein glückliches und erfolgreiches Miteinander. Wir sehen uns im neuen Jahr. ;-) (Der nächste Flurfunk Beitrag erscheint am 03. Januar!)

Spenden statt Präsente – unter diesem Motto unterstützt SDX seit 2006 die Aktion F.A.Z.-Leser helfen.

Share |

Alle Jahre wieder eine Überraschung! 16.12.2010

Svenja Henß
Svenja Henß, Senior Assistant

Das Marketing Team der SDX hatte sich auch für die diesjährige Weihnachtsfeier wieder eine Überraschung für die eXperts sowie deren Partner ausgedacht:
Mediterrane Weihnachten!

Nach der Begrüßung durch den überlebensgroßen Weihnachtsmann, genossen wir in mediterraner Atmosphäre und einigen Höhepunkten :-) die Weihnachtsfeier.

"Sei stolz auf dich, wenn du etwas erreicht hast".
Nach einem starken und überaus erfolgreichen Jahr 2010 sind wir dies.

Hier einige Impressionen:

comp_IMG_6672_DxO_raw comp_IMG_6674_DxO_raw comp_IMG_6693_DxO_rawcomp_IMG_6686_DxO_raw  comp_IMG_6698_DxO_raw comp_IMG_6696_DxO_raw  comp_IMG_6731_DxO_raw comp_IMG_6734_DxO

comp_IMG_6713_DxO_raw comp_IMG_6724_DxO_raw

Share |

WinForms/C#: Close-Button deaktivieren 15.12.2010

Matthias Jauernig
Matthias Jauernig, Senior eXpert

Manchmal ist es hilfreich, wenn man während der Ausführung eines Prozesses in seinem Programm den “Schließen”-Button der Anwendung deaktiviert. Direkt mit WinForms-Mitteln ist dies allerdings nicht möglich.

Daher bleibt nur der Weg über Win32-API-Funktionalität, wobei ein Aktivieren/Deaktivieren des Schließen-Buttons z.B. über folgendes Property “IsCloseButtonEnabled” erreicht werden kann:

   1: #region Win32 API Functions
   2:  
   3: private const int SC_CLOSE = 0xF060;  // ID des Schließen-Buttons
   4: private const int MF_ENABLED = 0x0;   // Wert, wenn Schließen-Button aktiv ist
   5: private const int MF_DISABLED = 0x2;  // Wert, wenn Schließen-Button inaktiv ist
   6:  
   7: [DllImport("user32.dll")]
   8: private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
   9: [DllImport("user32.dll")]
  10: private static extern int EnableMenuItem(IntPtr hMenu, int wIDEnable, int wValue);
  11:  
  12: #endregion
  13:  
  14: #region Properties
  15:  
  16: private bool _isCloseButtonEnabled = true;
  17: private bool IsCloseButtonEnabled
  18: {
  19:     get { return _isCloseButtonEnabled; }
  20:     set
  21:     {
  22:         if(_isCloseButtonEnabled == value)
  23:             return;
  24:         _isCloseButtonEnabled = value;
  25:  
  26:         IntPtr sysMenu = GetSystemMenu(Handle, false);
  27:         EnableMenuItem(sysMenu, SC_CLOSE, value ? MF_ENABLED : MF_DISABLED);
  28:     }
  29: }
  30:  
  31: #endregion
Allerdings kann der Benutzer das Programm immer noch über die Taskleiste oder das Kontextmenü beenden. Daher sollte in jedem Fall zusätzlich eine ordnungsgemäße Behandlung des Closing-Events der Form vorhanden sein…

Weiterhin ist anzumerken, dass ein einmaliges Deaktivieren des Schließen-Buttons nicht ausreicht. Verändert man die Größe der Form, minimiert oder maximiert sie, so ist der Button auf einmal wieder aktiviert! Daher ist es notwendig, einen Handler auf das Resize-Event der Form zu registrieren und dort den Schließen-Button immer wieder zu deaktivieren, wenn dies notwendig ist (d.h., wenn z.B. der Prozess aktiv ist, bei dem der Schließen-Button deaktiviert sein soll).

Share |

Konfigurierbare Dateisuche mit Foreach Loop 13.12.2010

Michael Beuss
Michael Beuss, Principal eXpert

Wer Dateien aus einem Verzeichnis mit SSIS verarbeiten möchte, verwendet üblicherweise einen Foreach Loop Container mit einem File Enumerator und gibt das Verzeichnis und die Dateimaske an. Leider lässt sich aber hier nur eine einzige Dateimaske verwenden. Doch was tun wenn ein Verzeichnis mehrere Dateien mit unterschiedlichen Namen enthält oder mehrere Verzeichnisse berücksichtigt werden sollen? Etwa mehrere Foreach Loop Container mit jeweils der gleichen Verarbeitung?

Abhilfe schafft hier das Zusammenspiel zweier Foreach Loop Container die aus einer XML Datei gespeist werden. Und das geht so:

  1. Anlegen eines äußeren Foreach Loop Containers, nennen wir ihn FLC DirSpec.
  2. Im Scope von FLC DirSpec zwei String-Variablen anlegen, und zwar FileSpec und Directory. Diese Variablen sollen mit Werten aus einer XML-Datei gefüllt werden und an die innere Loop weitergereicht werden.
  3. Anlegen einer XML-Datei, wobei Directory und FileSpec als Attribute angegeben werden.
       1: <?xml version="1.0" encoding="utf-8" standalone="yes"?>
       2: <Directories>
       3:  
       4:     <DirSpec Directory="D:\Testdir\Dir1" FileSpec="*.zip" />
       5:     <DirSpec Directory="D:\Testdir\Dir1" FileSpec="*.pdf" />
       6:     <DirSpec Directory="D:\Testdir\Dir2" FileSpec="*.bmp" />
       7:  
       8: </Directories>
  4. In der äußeren Loop FLC DirSpec den Enumerator NodeList einstellen und als EnumerationType ElementCollection auswählen. Als OuterXPathString wird mit DirectInput der Eintrag /Directories/DirSpec (siehe Struktur XML-Datei) angegeben und als InnerXPathString @* (alle Attribute) gesetzt. In Variable Mappings sollen entsprechend der Attribut-Reihenfolge in der XML-Datei die Variablen User::Directory und User::FileSpec eingetragen werden.
  5. Jetzt wird die innere Foreach Loop als FLC Filepath angelegt. Diese Loop ist vom Typ FileEnumerator und für die eigentliche Dateisuche verantwortlich. Dazu müssen im Expression Editor Directory und FileSpec auf die in Schritt 4 gefüllten User-Variablen zugeordnet werden.
  6. Anlegen einer Ergebnisvariable User::Filepath und diese eintragen in Variable Mappings bei FLC Filepath. Darin steht dann später bei Paketausführung der vollständige Pfad einer gefundenen Datei.
  7. Innerhalb von FLC Filepath kann nun die eigentliche Dateiverarbeitung platziert werden, die auf die Variable User::Filepath zugreift und für jede gefundene Datei aufgerufen wird. Das Paket sieht damit beispielsweise so aus:ForeachLoop

 

 

 

 

 

 

 

 

 

Ergebnis: Bei Paketausführung wird die XML-Datei von der äußeren Loop gelesen und das Verzeichnis und die Dateimaske jeweils an die innere Loop weitergegeben. Diese sucht dann in den realen Verzeichnissen nach entsprechenden Dateien. Für jede gefundene Datei wird die Verarbeitungsroutine aufgerufen.

Fazit: Durch die Kombination zweier Foreach Loop Container mit einer Konfigurationsdatei kann die Dateisuche sehr flexibel mit SSIS Bordmitteln verwirklicht werden. Es lassen sich auch weitere Konfigurationselemente hinzufügen um beispielsweise Rekursion bei der Dateisuche einzuschalten. Königsdisziplin ist natürlich die Entwicklung eigener Custom Components. Der Aufwand lohnt sich insbesondere wenn spezielle Anforderungen abgedeckt werden sollen und dies standardmäßig nicht ohne weiteres möglich ist.

Share |

“Windows Phone 7 beats iPhone 4 and Android…” 10.12.2010

Alexander Jung
Alexander Jung, Chief eXpert

Wir wussten es ja schon lange: Windows Phone 7 schlägt die Konkurrenz möglicherweise noch nicht beim Copy&Paste, aber bei den wirklich wichtigen Disziplinen hat Microsoft mal wieder die Nase vorne…

 

via engadget

Share |

C# 5: Es wird asynchron 08.12.2010

Matthias Jauernig
Matthias Jauernig, Senior eXpert

Am Anfang war C# 1 und brachte uns managed Code. Danach kamen die Generics mit C# 2, deklarative Programmierung in C# 3 und dynamische Programmierung in C# 4.

C# 5 wird uns wohl die asynchrone Programmierung vereinfachen. Dies zumindest hat Anders Hejlsberg, seines Zeichens Chefentwickler von C#, auf einer Session der PDC10 angekündigt und dabei auch bereits einige Beispiele vorgezeigt.

Bisher ist asynchrone Programmierung vielen Entwicklern immer ein Dorn im Auge und das zurecht. Methoden werden asynchron aufgerufen, kehren dann irgendwann zurück und ihre Ergebnisse müssen z.B. in einer Callback-Methode separat abgehandelt werden. Mit Lambdas gewinnt man hier ein wenig an Übersicht, das grundlegende Problem bleibt allerdings bestehen: Code lässt sich nicht mehr sequentiell in logischer Abfolge schreiben und wird damit unleserlich(er) und schlechter wartbar. Auch Dinge wie Fehlerbehandlung wollen hier richtig implementiert sein.

Für C# 5 sind zwei neue Schlüsselwörter async und await angekündigt, welche dieses Problem angehen sollen (wobei sich die Syntax aufgrund des frühen Stadiums der Entwicklung noch ändern kann). Sie bauen auf Features von .NET 4.0 auf, die in der Task Parallel Library (TPL) vorhanden sind, brechen diese nun allerdings auf Sprachenebene herunter, was Asynchronität sehr elegant macht.

Mit async werden dabei Methoden deklariert, die irgendeinen asynchronen Kontrollfluss beinhalten, selber aber nicht unbedingt asynchron aufgerufen werden müssen. async Methoden beinhalten ein oder mehrere await Statements, welche die eigentliche asynchrone Verarbeitung abstrahieren. Mit async weiß der Compiler, dass er die entsprechende Methode in einen Zustandsautomaten übersetzen muss, der im Prinzip das Gleiche macht wie der Programmierer bisher manuell: Callbacks setzen und bei Rückkehr der asynchronen Funktionalität aufzurufen... async Methoden müssen als Rückgabewert void, Task oder Task<T> haben, doch dazu später noch mehr...

await gibt einen Punkt in einer async Methode an, an dem tatsächlich eine asynchrone Funktionalität aufgerufen wird. await sagt dabei: "rufe diese Methode asynchron auf und setze bei ihrer Rückkehr an dieser Stelle fort". Die Implikation davon: man kann Code wie bisher sequentiell schreiben, um die Asynchronität und deren Abarbeitung kümmert sich der Compiler!

Es sei mal an einem Beispiel illustriert, das im Async Whitepaper enthalten ist.

Nehmen wir folgende synchrone Methode:

   1: public int SumPageSizes(IList<Uri> uris) {
   2:     int total = 0;
   3:     foreach (var uri in uris) {
   4:         statusText.Text = string.Format("Found {0} bytes ...", total);
   5:         var data = new WebClient().DownloadData(uri);
   6:         total += data.Length;
   7:     }
   8:     statusText.Text = string.Format("Found {0} bytes total", total);
   9:     return total;
  10: }

Diese kann mit den neuen Schlüsselwörtern wie folgt in eine asynchrone Methode umgewandelt werden:

   1: public async Task<int> SumPageSizesAsync(IList<Uri> uris) {
   2:     int total = 0;
   3:     foreach (var uri in uris) {
   4:         statusText.Text = string.Format("Found {0} bytes ...", total);
   5:         var data = await new WebClient().DownloadDataAsync(uri);
   6:         total += data.Length;
   7:     }
   8:     statusText.Text = string.Format("Found {0} bytes total", total);
   9:     return total;
  10: }

Und das war’s! Die gelben Markierungen geben alle Änderungen im Vergleich zum Code darüber an, die notwendig waren, um den Code asynchron zu machen. Die Sequentialität und die Übersichtlichkeit des Codes bleiben dabei voll gewahrt! await kommt beim Aufruf der asynchronen Methode DownloadDataAsync() zum Einsatz. Es wartet an dieser Stelle nicht (!) auf die Rückkehr der Methode, denn dann wären wir wieder in der synchronen Welt. Im Gegensatz dazu ist es nur eine Anweisung für den Compiler bei Rückkehr der Methode an dieser Stelle weiterzumachen. Dabei können die Rückgabewerte der Methode direkt an eine Variable zugewiesen werden, Auswertungen á la e.Result entfallen!

So elegant ich das finde, zwei Dinge habe ich festgestellt, die mich erstmal zum Nachdenken gebracht haben:

  1. async Methoden müssen beim Aufrufer IMMER mit einem await abgehandelt werden. Das impliziert Folgendes: wenn ich eine Aufrufkette von meiner UI über 5 Methoden an meinen Datenzugriff habe und dort eine async Methode definiere, dann müssen ALLE Methoden der Aufrufkette async sein und mit await die Ergebnisse der Methoden darunter abarbeiten. Das fühlt sich für mich erstmal komisch an, andererseits ist es auch genau das, was man machen müsste, wenn man manuell Asynchronität behandelt und dabei Ergebnisse über die Aufrufkette hinweg zum UI bringen will. Hat man sich daran gewöhnt, sollte es kein Problem sein...
  2. Nehmen wir obiges Beispiel: der Rückgabewert der async Methode ist zwar Task<int>, de facto wird vom Code mit "int total" aber ein Integer-Wert zurückgegeben. Wie das? Die async Methode wird vom Compiler umgeschrieben und gibt daher einen Task<T> zurück, auch wenn im Code etwas anderes steht. Aber es gibt hier einen Mismatch zwischen Deklaration und tatsächlicher Definition, was ich auch als äußerst gewöhnungsbedürftig sehe. Hier sehe ich Entwickler, die mit diesem Konzept überfordert sein könnten...

Alles in allem bleibt meine Aussage trotzdem bestehen: ich halte das für eine echt coole Sache! Gerade in der heutigen immer asynchroner werdenden Welt zwischen Cloud, Silverlight und Windows Phone 7 ist solch ein "syntactic sugar" mehr als überfällig...

Btw: Die neuen Schlüsselwörter können direkt ausprobiert werden. Einfach die Async CTP herunterladen und loslegen: Async CTP

Share |

SQL Azure Reporting auf der PDC 2010 06.12.2010

Boris Borgner
Boris Borgner, Senior eXpert

Pünktlich zur PDC 2010 stellt Microsoft eine erste CTP der SQL Azure Reportingdienste vor. Damit beschreitet Microsoft einen ersten Schritt in Richtung Business Intelligence in der Cloud. Mehr Informationen gibt es in diesem Video. Interessierte können sich bei Microsoft für diese CTP registrieren, die es bis Ende des Jahres geben soll. Mit SQL Azure Reporting können Berichte entweder mit dem BI Development Studio (BIDS) oder dem Report Builder gegen Azure Datenquellen entwickelt und direkt aus BIDS auf das Azure Portal geladen werden. Diese Berichte können dann sowohl über das Azure Portal angezeigt werden, als auch direkt in eigene Anwendungen integriert werden.

Folgend ein Vergleich zwischen den SQL Server Reporting Services (SSRS) und SQL Azure Reporting:

Capability SQL Server Reporting Services SQL Azure Reporting
Developer design tool BIDS Report Builder BIDS Report Builder (Authoring only - deployment to SQL Azure Reporting through BIDS)
Supported data sources Diverse data sources SQL Azure databases
Report Embed reports into your apps Embed hosted reports into your apps
Management and delivery Report Manager or SharePoint Portal display reports rendering to multiple formats subscriptions scheduled delivery SQL Azure Development Portal display reports rendering to multiple formats
Developer Extensibility Extensible for custom data sources, assemblies, report items, authentication, etc. Extensibility is not yet enabled
Security Model Windows Authentication SQL Azure Username/password

Mehr zu SQL Azure Reporting gibt es direkt bei Microsoft und im Blog von Steffen Krause.

Share |

Convention over Configuration Begriffserklärung 03.12.2010

Gerrit Puddig
Gerrit Puddig, Principal eXpert

Die meisten Frameworks benötigen eine umfangreiche Konfiguration um zu funktionieren. Für Entwickler ohne ausreichende Erfahrung kommt es hierbei häufig zu Verständnisproblemen. Die Hürde für den Einstieg muss genommen werden und nicht selten verzweifelt manch einer und stoppt das Projekt "Neues Framework evaluieren" mit dem Fazit: unbrauchbar.

Natürlich versuchen viele Frameworks deshalb den Einstieg so leicht wie möglich zu machen und nehmen Standardwerte für die meisten Einstellungen an. Diese können bei Bedarf vom Entwickler punktuell oder komplett angepasst werden.

Kunde_1[6] Kunde_2[3]
Dieses Problem existiert genauso in Bezug auf Nutzung von Framework Komponenten. Hier muss ein Interface ausimplementiert, dort ein Property mit einem passenden Wert versehen werden. Um diesen Problemen zu begegnen, setzen mittlerweile einige Frameworks auf "Convention over Configuration". Ein Vorgehen, bei welchem das Framework gewisse Annahmen trifft, welche bei Bedarf vom Entwickler genutzt werden können. So abstrakt diese Aussage klingt, so einfach lässt sich das Ganze an einem Beispiel beschreiben: Geht man von einem Framework für Objektpersistenz (z.B. Entity Framework) aus, so erwartet dieses für alle zu speichernden Objekte eine eindeutige Id. Diese wird zur Identifizierung der Objekte genutzt. Hierzu muss zuerst eine Konfiguration erstellt werden, welche dem Entity Framework für jeden Typen das identifizierende Property aufzeigt. Das kann über ein Attribut erfolgen, XML Konfiguration, eine externe Mapping-Klasse, etc. Am Beispiel eines Kundenobjekts (Abbildung 1) muss das Property Kundennummer konfiguriert werden. Da diese Mapping-Konfiguration für jeden Typen erfolgen muss, steigt der Aufwand proportional mit der Größe der Solution. Es stellt sich die Frage, ob hierfür nicht eine Konvention genutzt werden kann. Diese gibt vor, dass falls ein Objekt eine Property mit Namen ID enthält, diese automatisch als Identifier angenommen wird, ohne dass eine extra Konfiguration notwendig ist (Abbildung 2). Der Entwickler muss somit dafür sorgen, dass seine Objekte alle das Property ID haben.

Zugegebenermaßen klingt das ein wenig nach Gängelung. Was, wenn wir einen Composite Key, also Eindeutigkeit über mehrere Felder haben. Wenn also eher mit fachlichen Schlüsseln zur Identifikation gearbeitet wird? Auch wenn ein Surrogate Key (technischer Schlüssel) die empfohlene Vorgehensweise darstellt, kommen die fachlichen Schlüsselkombinationen in freier Wildbahn häufig vor. Hierfür können explizite Mappings definiert werden, welche dann Priorität genießen. Spezialisierung vor Allgemein, sozusagen. Der entscheidende Punkt ist hierbei, dass Konventionen allgemeine Annahmen darstellen, welche - wenn notwendig - angepasst werden können.

Nachdem die Begrifflichkeit "Convention over Configuration" hiermit erläutert wurde, folgen in einem der nächsten Einträge konkrete Konventionen im Feature CTP 4 Release des neuen Entity Frameworks.

Share |

Silverlight 5 bei Firestarter-Event angekündigt 02.12.2010

Patric Schouler
Patric Schouler, Chief eXpert

Beim heutigen Firestarter-Event von Microsoft wurden die Haupt-Features von Silverlight 5 in der Keynote von Scott Guthrie angekündigt. Silverlight 5 (SL5) wird in einer Beta-Version im Frühjahr 2011 erscheinen. Die endgültige Version soll dann in der zweiten Jahreshälfte veröffentlicht werden. Silverlight 5 wird über 40 neue Funktionen enthalten, von denen die wichtigsten nachfolgend dargestellt werden:

Silverlight 5 bietet eine verbesserte Medien-Unterstützung:

  • Hardware-Decode verbessert die Performance von High-Definition Video auch auf schwächerer Hardware.
  • TrickPlay ermöglicht es, Videos mit verschiedenen Geschwindigkeiten abzuspielen und unterstützt schnelles Vor-und Zurückspielen. Bei bis zu doppelt so schneller Geschwindigkeit erlaubt es Silverlight 5 mit Audio Pitch Korrekturen Videos zu betrachten und gleichzeitig eine normale Tonhöhe beizubehalten.
  • Verbesserte Energieverbrauchsüberwachung verhindert, dass der Bildschirmschoner angezeigt wird, während Videos abgespielt werden und erlaubt dem Computer in den Ruhezustand zu gehen, wenn Video nicht aktiv ist.
  • Fernbedienung-Unterstützung erlaubt Benutzern, die Medienwiedergabe (fern) zu steuern.

Die wichtigsten Neuerungen von Silverlight 5 im Bereich Silverlight Business Applications Development umfassen:

  • Databinding und MVVM: Silverlight 5 liefert viele Verbesserungen zum Data-Binding zur Erhöhung der Entwicklungsprodukivität und Vereinheitlichung von Silverlight und WPF Mechanismen
  • WCF und RIA Services:Unterstützung von komplexen Datentypen und bessere Unterstützung von MVVM. Netzwerkverbesserungen und Optimierungen für niedrige Übertragungsraten.
  • Text und Printing: Klarere Textdarstellung, OpenType-Unterstützung und eine neue Postscript Vektor API
  • Pivot: Unterstützung für reichhaltige Reports
  • Graphics: volle Kontrolle über die GPU (graphics processing unit) mit beschleunigter 3-D Unterstützung
  • Out of Browser: Unterstützung von Child Windows, P/Invoke zum Aufruf von unmanaged Libraries und der Nutzung von Win32 APIs
  • Testing Tools: Automatisierte Test-Unterstützung für Visual Studio 2010
  • Performance: Silverlight 5 unterstützt schnellere Programmstarts und 64-bit Browser sowie die Hardware Beschleunigungs-Mechnismen des IE9

Weitere Informationen: Announcing Silverlight 5 - ScottGu's Blog und The Future of Microsoft Silverlight | Microsoft Silverlight



         

Share |

Timeout-Exception bei Transaction-Rollback 01.12.2010

Matthias Jauernig
Matthias Jauernig, Senior eXpert

Als Entwickler sieht man sich tagtäglich mit neuen Herausforderungen konfrontiert, deren Lösung meist eine zeitaufwändige Fehleranalyse beinhaltet.

So auch bei einem meiner aktuellen Probleme. Die Herausforderung stellte ein .NET-Programm mit einer langlaufenden Transaktion auf dem SQL Server dar, in die eine ganze Menge an Daten geschrieben wurden. Dies stellt in dem Kontext der Anwendung kein Problem dar und ist aufgrund des Prozesses kaum vermeidbar. Zu Test- und Entwicklungszwecken ließ ich diese DbTransaction bei Beendigung der Verarbeitung einen Rollback() durchführen.

Und hier lag auch schon das Problem. Gelegentlich und ohne erkennbares Muster warf die Rollback()-Methode eine SqlException, die einen Timeout der Aktion nahelegte:

Message: 
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
 
StackTrace: 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) 
    at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParserStateObject.ReadPacket(Int32 bytesExpected) at System.Data.SqlClient.TdsParserStateObject.ReadBuffer() 
    at System.Data.SqlClient.TdsParserStateObject.ReadByte() 
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
    at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) 
    at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) 
    at System.Data.SqlClient.SqlInternalTransaction.Rollback() at System.Data.SqlClient.SqlTransaction.Rollback()

Nach langer langer Fehleranalyse und Google-Suche stieß ich dann auf einen MSDN-Forum-Eintrag, der genau dieses Problem thematisiert. Im darin enthaltenen Quellcode der SqlInternalConnection.ExecuteTransactionYukon()-Methode des .NET-Frameworks ist erkennbar, dass als Timeout für die Rollback-Aktion der eingestellte ConnectionTimeout verwendet wird!

Das ist schon verwunderlich! Der ConnectionTimeout ist eigentlich dafür gedacht, die maximale Zeit zum Herstellen einer Verbindung zum DB-Server festzulegen. Hingegen wird er hier für den Timeout der Rollback-Aktion quasi missbraucht, was intuitiv so nicht erwartet wird.

Eine Rollback-Aktion kann im Vergleich zu einem Commit einer Transaktion durchaus einige Zeit dauern, die voreingestellten 15 Sekunden ConnectionTimeout führten hier sporadisch zu einer Exception. Nach einem moderaten Anheben des Timeouts über den Connection String konnte das Problem behoben werden.

Share |