Archiv

Archiv für die Kategorie ‘Entwicklung’

SQL Deadlock durch Autoclose

9. Januar 2014 Keine Kommentare

Seit einigen Monaten nervte in einer Microsoft SQL 2008 Datenbank ein Problem, welches gelegentlich auftrat. Auf die betreffende Datenbank waren ab einem scheinbar zufälligen Zeitpunkt keine schreibenden Zugriffe mehr möglich, lesende Zugriffe aber schon. Ein einfacher Blick nach der Verfügbarkeit reichte also nicht, um die Lauffähigkeit der Datenbank zu testen.

Ein Blick in die Log-Dateien brachte die Erkenntnis, dass diese Datenbank ziemlich oft gestartet wurde (im Gegensatz zu den anderen Datenbanken) und plötzlich ein Fehler 1205 auftrat:

Transaction (Process ID …) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Danach war die Datenbank schreibend nicht mehr verfügbar, der Fehler 9001 trat auf:

The log for database ‚…‘ is not available. Check the event log for related error messages. Resolve any errors and restart the database.

Select – Abfragen waren davon aber nicht betroffen, da diese ja keine Log-Einträge erzeugen.

Die Lösung wurde in SQL ServerCentral.com beschrieben: Abschalten der Option AutoClose in den Eigenschaften der Datenbank! Da diese Eigenschaft weder bewußt gesetzt worden war, noch benötigt wurde, konnte das Problem so einfach gelöst werden.

KategorienDatenbank Tags: ,

ASP.NET MVC und Login Cookie

26. Dezember 2013 Keine Kommentare

Vor kurzem wurde ich von einer Anfrage eines Kunden überrascht. Eingaben auf meiner MVC Seite nach einer längeren Wartepause, die durchaus im Bereich von Stunden liegen kann, führten wieder zum Login. Da wir keine Daten in Sessions gespeichert haben, konnte ich mir das Verhalten erst nicht erklären. Ich bin immer davon ausgegangen, dass ein POST alle notwendigen Daten überträgt. Bei den Login-Informationen passte hier wohl etwas nicht wie erwartet. Also habe ich das ganze analysiert:

Bei einer MVC 3 oder 4 Webseite mit Formular-Authentifizierung wird folgender Code zum Setzen der Authentifizierungsinformationen aufgerufen:

FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);

Wählt der Anwender nun die Option Speichern nicht aus, so wird beim Authentifizierungscookie automatisch die Verfallsinformation auf Session gesetzt. Da Sessions in der Standardeinstellung nach 20 Minuten Inaktivität verfallen, erklärt es auch, warum nach längerer Pause die Anmeldung ungültig wurde:

FormsAuthentication.SetAuthCookie(model.UserName, false);

Cookie ohne Speichern

Besser sieht es jedoch auch, wenn die Anmeldeinformationen gespeichert werden dürfen:

FormsAuthentication.SetAuthCookie(model.UserName, true);

Dann wird das Authentifizierungscookie automatisch mit dem Verfallsdatum des Timeouts der Web.config gesetzt, hier 2880 Minuten => 2 Tage.

  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>
  </system.web>

Cookie mit Speichern

Mir persönlich fehlt jetzt noch die Option, dass Authentifizierungscookie bis zum Ende der Browsersitzung behalten zu können, aber man kann scheinbar nicht alles haben.

KategorienMicrosoft .NET Tags: ,

Administratorzugriff auf SQL Server wiederherstellen

18. September 2013 Keine Kommentare

Manchmal ist man in der Situation, dass man keinen Zugriff mehr auf einen SQL Server mehr hat, obwohl man selbst Administrator der darunter liegenden Windows-Version ist. In diesem Fall hat Microsoft dafür gesorgt, dass man recht einfach die Administrationsrechte für den SQL Server erlangen kann. Der meiner Meinung nach einfachste Weg geht so:

SQL-Server-KonfigurationsmanagerMan startet den SQL-Server-Konfigurationsmanager und öffnet die Eigenschaften des gewünschten SQL-Dienstes. Bei aktuellen Version hat man nun die Möglichkeit, direkt den Parameter -m hinzuzufügen. Dieser Parameter startet den SQL-Server Einzelbenutzermodus und gibt allen lokalen Administratoren Zugriff. Alternativ muss man bei älteren Versionen auf der Seite erweitert den Parameter direkt in der Auflistung angeben. Aber Achtung, dort werden die Parameter mit ; getrennt. Es muss dann also lauten:

-m;--dC:\Program Files\Microsoft S...

Anschließend muss der Dienst neu gestartet werden. Nun kann man sich mit dem SQL Server Managementstudio direkt verbinden. Aber auch hier Achtung: Das Programm muss dazu unbedingt als Administrator gestartet werden, selbst wenn unter Windows als Admin angemeldet ist! Nun kann man seinen Admin-Login hinzufügen und mit den notwendigen Rechten versehen. Zum Abschluss nicht vergessen, den Parameter -m wieder zu entfernen, damit der Server normal zur Verfügung steht.

KategorienDatenbank Tags: ,

Genaues Erstellungsdatum mit DIR anzeigen

2. August 2013 Keine Kommentare

Ich benötigte für eine Überprüfung von Dateien auf einem Server das exakte Datum der Erstellung. Ein Blick in die Optionen von DIR oder die Eigenschaften der Datei zeigte aber immer nur Informationen auf die Minute genau an, ich brauchte aber zur sinnvollen vergleichenden Bewertung der Performance die Sekunden-Bruchteile.

Nach etwas erfolgloser Suche habe ich mir das in der Powershell selbst zusammengebastelt:

Get-ChildItem | Sort-Object CreationTime |
 Format-Table Name,@{Expression={$_.CreationTime};FormatString="mm/ss/ff"}

Damit bekommt man wie bei Dir auch alle Dateien in einem Verzeichnis angezeigt, dass ganze wird nach dem Erstelldatum sortiert und mit dem Erstelldatum in Minuten/Sekunden/Sekundenbruchteilen ausgegeben. Bei der Formatierung der Uhrzeit hat man so natürlich viele Möglichkeiten.

KategorienAllgemein, Toolbox Tags:

Fehlermeldung beim Einbinden SqlExpr.pas

5. November 2012 Keine Kommentare

Der Versuch, eine alte Anwendung auf einer frischen Delphi 7 Installation zu erstellen, brachte sofort beim Einbinden der Unit SqlExpr eine Fehlermeldung:

Unit SqlExpr wurde mit einer unterschiedlichen Version von SqlConst.SNOERROR compiliert

Leider haben mir der Tipp auf Delphipraxis nur bedingt weitergeholfen. Dazu soll folgender Code:

SNOERROR ='';
SWARNING ='';
SCONNECTIONFAILED ='';
SDRIVERINITFAILED ='';
SOPTLOCKFAILED ='';
SINVALIDREF ='';
SNOTABLE ='';
SDBXError ='';
SNODATA ='';
SSQLERROR ='';
SSQLServerError'';

in der SqlConst.pas im Source\VCL Ordner eingefügt werden und das ganze erzeugt und nach {Delphi}\Lib und {Delphi}\Lib\Debug verteilt werden. Wie man diese Unit aber erzeugt, stand leider nicht dabei und es ist mir auch nicht gelungen, den Code habe ich trotzdem eingefügt, da diese pas-Datei im Suchpfad ist.

In der Entwickler Ecke habe ich dann den nächsten Tipp gefunden:

Das nächste Problem scheint DBExpress zu sein, einige Projekte konnten nicht kompiliert werden, da SqlExpr.dcu mit einer anderen Version kompiliert wurde. Den Fehler konnte ich mittlerweile beheben, das Update hat im Verzeichnis $(DELPHI)\lib\ eine Datei SqlConst.dcu.de angelegt. Ich habe die Datei SqlConst.dcu dann nach SqlConst.dcu.org umbenannt und SqlConst.dcu.de nach SqlConst.dcu. Das gleiche auch nochmal im Verzeichnis $(DELPHI)/lib/debug.

Nachdem ich auch diese Umbenennung durchgeführt habe, klappte es wieder wunderbar. Der Fehler scheint übrigens irgendwie mit der deutschen Lokalisierung vom ServicePack 1 für Delphi 7 im Zusammenhang zu stehen.

KategorienDelphi Win32 Tags:

.NET Open Space Süd 2012 in Karlsruhe

Eigentlich leide ich zur Zeit unter notorischem Zeitmangel. Aber das .NET Open Space in Karlsruhe habe ich mir dieses Jahr nicht nehmen lassen. Nachdem ich letztes Jahr nicht teilnehmen konnte, war es für mich der zweite Besuch. Viele Gesichter kannte ich aus diesem Grund schon. Die Veranstaltung wurde wieder in den Räumen von bluehands ausgerichtet. Ich finde das nach wie vor beachtlich, alles einfach mal so umzuräumen. Danke!
Die Themen wurden von den 70 Teilnehmern wieder selbst bestimmt und wie auch schon 2010 war es kein Problem, ausreichend Themen für die Agenda zu finden. Neuer großer Schwerpunkt war ganz klar die Entwicklung für Smartphones. Kaum einer kann sich der Problematik momentan entziehen und irgendwo ist mit dem Windows 8 Tablet ja auch von Microsoft etwas im Anmarsch, was deren Windows Phone pushen könnte. Interessant war in diesem Fall die aktuelle Dominanz von Apple-Hardware, zeitweise waren auf dem Openspace 80% der Notebooks und Tablets von Apple. Auf alle Fälle durften wir diesbezüglich einen guten Einblick in die Entwicklung für Android und Apple-Smartphones mit Xamarin gewinnen.
Christina Hirth griff das Thema CleanCode(Developer) auf, was eine sehr intensive Diskussion in Gang brachte. Es herschte eine Einigkeit darüber, dass den meisten Teilnehmer vom #nossued das Thema wohl geläufig ist. Eine gute Möglichkeit, dieses in Firmen einzubringen, könnten Coding Dojos sein.

Pfadnamen für Ausgabe kürzen

15. Dezember 2011 Keine Kommentare

Im Microsoft .NET Framework ist schon lange eine Funktion zum Kürzen von Dateinamen enthalten. Aus c:\Windows\System32\MyDll.dll kann dann zum Beispiel c:\Windows\…\MyDll.dll werden. Hierzu greift man auf TextRenderer.MeasureText zurück. Allerding hat diese Funktion einen kleinen Fehler bei dem zurückgegebenen Wert, der hier beschrieben ist:

Der Workaround ist zum Glück auch gleich angegeben, und kann dann so aussehen:

string filename = string.Copy(filenameForOutput);
if (!string.IsNullOrEmpty(filename))
{   
   TextRenderer.MeasureText(filename, Font, Size,
     TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);
   filename = filename.Substring(0, filename.IndexOf('\0'));
}

Der Source zeigt auch gleich noch eine kleine andere Ergänzung: Die Funktion modifiziert den übergebenen String. Man sollte diesen also vorher kopieren, sofern man nicht schon mit einer Kopie des Strings arbeitet.

KategorienMicrosoft .NET Tags: ,

Bestimmen einer Zeitdifferenz mit SQL

24. Oktober 2011 Keine Kommentare

Eine Abfrage im SQL Server enthält eine time-Spalte:

SELECT [Activity], [Duration] FROM TableName

Die Aufgabenstellung bestand darin, die Zeiten zu addieren. Leider wurde dieser Versuch

SELECT SUM([Duration]) FROM TableName

abgelehnt:

Der Operanddatentyp time ist für den sum-Operator ungültig.

was zwar nicht einleuchtend, aber auch nicht zu ändern war.
Die Lösung war die vorherige Umwandlung der Zeit in eine Datumsdifferenz vom Typ Minuten:

SELECT SUM(DATEDIFF(MINUTE, '00:00:00', [Duration])) FROM TableName
KategorienDatenbank Tags:

Manuelles schreiben einer lokalen Url in Asp.NET

23. September 2011 1 Kommentar

Glaubt man der Dokumentation von HttpRequest.ApplicationPath, so ist es recht einfach, einen Link in einer eigenen Asp.NET Seite zu verwenden:

Label1.Text = Request.ApplicationPath;
Image1.ImageUrl = Request.ApplicationPath + "/images/Image1.gif";
Label2.Text = Image1.ImageUrl;

Aber damit steht man schnell vor einem Problem: Liegt die Anwendung im Root, wie es beispielsweise standardmäßig beim Visual Studio 2010 Development Server der Fall ist, so erhält man als Ergebnis nur ein /. Die korrekte Zeile wäre dann also:

Image1.ImageUrl = Request.ApplicationPath + "images/Image1.gif";

Befindet sich die Seite aber in einem virtuellen Verzeichnis, so kommt das Verzeichnis ohne abschließenden / zurück:

Image1.ImageUrl = Request.ApplicationPath + "/images/Image1.gif";

Je nach Speicherort muss man also beim händischen Zusammensetzen der URL’s also den abschließenden Slash berücksichtigen, oder eben auch nicht.

Eine gute Lösung habe ich in einem Blog-Artikel von 2004 gefunden:

VirtualPathUtility.ToAbsolute("~/images/Image1.gif")

Damit überlässt man Asp.NET die korrekte Umsetzung, welche auch tadellos und ohne Experimente funktioniert!

Update:
Manchmal sieht man einfach den Wald vor lauter Bäumen nicht. Die kürzere Lösung ist Url.Content, welche ein vergleichbares Ergebnis liefert und auch in den Templates von Asp.NET MVC3 verwendet wird.

KategorienAllgemein, Microsoft .NET Tags: ,

Vererbung von Properties entfernt die Attribute

Für eine Erweiterung von meinem Quellcode hatte ich geplant, ein paar Properties mit Attributen zu versehen. Dabei sollten die Properties virtual sein. Die Abfrage der Attribute sollte dann mittels GetCustomAttributes geschehen. Leider hat das gar nicht funktioniert, was auch schon andere .NET-Programmierer feststellen mussten. Darum habe ich die Problemstellung extrahiert:

Zum Prüfen der Attribute wurde folgende Funktion verwendet:

static void CheckAttribute(MemberInfo memberInfo)
{
    var attributes = memberInfo.GetCustomAttributes(true);
    if (attributes.Length == 0) return;
 
    foreach (object attribute in attributes)
        Console.WriteLine("The type of the attribute in {1} is {0}.", 
            attribute, memberInfo.Name);
}

Weiterhin wurden zwei Klassen geschrieben, wo einmal eine abgeleitete Methode und eine abgeleitete Propertie mit Attributen versehen wurde:

public abstract class BaseClass
{
    [TestAttribute]
    public virtual String TestProperty { get; set; }
 
    [TestAttribute]
    public virtual void TestMethod() { return; }
}
public class DerivedClass : BaseClass
{
    public override string TestProperty { get; set; }
    public override void TestMethod() { base.TestMethod(); }
}
 
public class TestAttribute : Attribute
{
}

Zu guter Letzt wurde das ganze überprüft:

Console.WriteLine("BaseClass:");
CheckAttribute(typeof(BaseClass).GetProperty("TestProperty"));
CheckAttribute(typeof(BaseClass).GetMethod("TestMethod"));
 
Console.WriteLine("DerivedClass:");
CheckAttribute(typeof(DerivedClass).GetProperty("TestProperty"));
CheckAttribute(typeof(DerivedClass).GetMethod("TestMethod"));

Das Ergebnis fiel überraschend aus:

BaseClass:
The type of the attribute in TestProperty is TestAttrib.TestAttribute.
The type of the attribute in TestMethod is TestAttrib.TestAttribute.
DerivedClass:
The type of the attribute in TestMethod is TestAttrib.TestAttribute.

Wähernd die Methode TestMethod in beiden Klassen als mit dem Attribut ausgezeichnet, erkannt wurde, war dies bei der Eigenschaft TestProperty nicht der Fall. Um die Ursache zu finden, war ein Blick in die IL notwendig. Hier die Umsetzung der BaseClass, welche das Attribute in beiden Fällen korrekt definiert.

.method public hidebysig newslot virtual instance void TestMethod() cil managed
{
    .custom instance void TestAttrib.TestAttribute::.ctor()
}
 
.property instance string TestProperty
{
    .get instance string TestAttrib.BaseClass::get_TestProperty()
    .set instance void TestAttrib.BaseClass::set_TestProperty(string)
    .custom instance void TestAttrib.TestAttribute::.ctor()
}

Die Ableitung war aber überaschend umgesetzt. Während die Methode offensichtlich überschrieben wurde, wurde die Propertie quasi neu angelegt, aber ohne dem zugewiesenen Attribut.

.method public hidebysig virtual instance void TestMethod() cil managed
{
}
 
.property instance string TestProperty
{
    .get instance string TestAttrib.DerivedClass::get_TestProperty()
    .set instance void TestAttrib.DerivedClass::set_TestProperty(string)
}

Damit war das Ergebnis der Untersuchung: GetCustomAttributes hat definitionsgemäß auch die Ableitungen untersucht. Jedoch verlieren sich die Attribute beim Überschreiben von Properties. Eine Erklärung dafür habe ich bis jetzt nicht gefunden, ich konnte den Effekt aber in .NET 2.0 – 4.0 nachstellen.