Archiv

Archiv für die Kategorie ‘Microsoft .NET’

Große Aufzählungen im .NET Framework

Neulich wurde ich mit der Definition einer besonders umfangreichen Aufzählung konfrontiert. Da hierfür die magische 32Bit Grenze überschritten wurde, war ich skeptisch. Ein Test ergab, das diese Skepsis in der Tat berechtigt war. Folgende Deklaration:

public enum Big
{
    Small = 1 << 1,
    Medium = 1 << 8,
    Large = 1 << 40
}

erzeugt dann das Problem. Bis hier:

var enumTest = Big.Small;
Debug.Assert(enumTest == Big.Small);
enumTest = Big.Medium;
Debug.Assert(enumTest == Big.Medium);
enumTest = Big.Large;
Debug.Assert(enumTest == Big.Large);

erscheint alles in Orndung, ein Ausgabetest:

var enumTest = Big.Small;
Console.WriteLine(enumTest);
enumTest = Big.Medium;
Console.WriteLine(enumTest);
enumTest = Big.Large;
Console.WriteLine(enumTest);

zeigt aber dann das Problem. Die Definition Medium und Large sind intern identisch:

Small
Medium
Medium

Zur Lösung des Problems muss man zwei Änderungen durchführen. Einmal ist der Aufzählungstyp von long abzuleiten und die Basiszahl für die Bitverschiebung muss ebenfalls eine long-Zahl sein:

public enum Big: long
{
    Small = 1L << 1,
    Medium = 1L << 8,
    Large = 1L << 40
}

Das Ergebnis bestätigt die korrekte Ausführung. Bei der Nutzung von 64 Bit ist aber dann vorerst wirklich Schluss!

KategorienMicrosoft .NET Tags: ,

NDepend, ein Einblick

27. April 2014 Keine Kommentare

Als ich vor kurzem gebeten wurde, mir NDepend anzuschauen, sagte ich sofort zu. Diese Software versprach mir Unterstützung in der Entwicklung und Überwachung von sauberem Code, ganz im Sinne von CCD. Nach dieser Sichtung habe ich verstanden, dass die Autoren der Software eine großartige Arbeit geleistet haben. Man erhält ein ungeheuer ausgefeiltes Stück Software, das den Entwickler zu Anfang mit der Fülle und dem Umfang von Dialogen und Optionen schlicht überfährt. Man lernt aber schnell, dass es scheinbar unvermeidbar war, damit die Software in unterschiedlichen Bedingungen eingesetzt werden kann. Ich rate jedem, der seinen NET-Sourcecode verbessern möchte oder im Team Fehlentwicklungen im Auge behalten will, sich die Zeit der Einarbeitung zu nehmen. Es lohnt sich!

Überprüfung des eigenen Codes

Als Einstieg sollte man sich diese Seite anschauen: GettingStarted. Dort wird als Video und alternativ in einer reich bebilderte Anleitung dargestellt, wie leicht NDepend mit dem eigenen Projektmappen verbunden werden kann. Dieser Vorgang funktioniert sehr gut und schnell. Die Original-VS-Projekte werden nicht angefasst, die NDepend-Verknüpfung kann auch leicht wieder gelöst werden. Eine SVN-Integration wird dadurch nicht beeinträchtigt.

NDepend DashBoardDann kann man sich bereits mittels des über das NDepend-Menü erreichbaren DashBoards einen Überblick verschaffen. Diese Beispielgrafik von NDepend stellt natürlich einen späteren Stand dar, zeigt aber die Fülle Informationen: Für mich war besonders wichtig, dass man sogar einen Überblick erhält, ob im Lauf der Zeit immer mehr Regeln verletzt wurden. Das hilft in der Team-Kontrolle! Weiterhin kann aus diesem DashBoard heraus leicht geprüft werden, welche Regeln verletzt wurden und vor allen Dingen: an welcher Stelle im Source! Regeln, welche man nicht für wichtig erachtet, kann man leicht deaktivieren. Alle Regeln liegen auch in einer gut kommentierten LINQ-ähnlichen Sprache vor, was die Anpassung leicht macht. Hier steht zusätzlich zu jeder NDepend eigenen Funktion eine gute Hilfe im Maus-Tooltip zur Verfügung.

Vergleichen der Entwicklungsgeschichte

NDepend Historic Analysis ResultMan stellt schnell fest, dass es nicht immer sinnvoll und praktikabel ist, gleich den kompletten Code Regelkonform zu gestalten, sprich alle Regel-Verletzungen zu entfernen. NDepend bietet hier die Möglichkeit, Basisstände als Vergleich heranzuziehen. Somit werden nur noch neuere Regelverletzungen angezeigt, was natürlich gerade für den Start sinnvoll ist. Als Start kann man dazu, wie in der nebenstehenden Grafik dargestellt, die historische Speicherung der Werte auf Always stellen. Damit hat man bereits nach der ersten NDepend-Überprüfung einen Vergleichsstand zur Verfügung, was den Start stark erleichtert.

Bewertung
NDepend eignet sich nicht für den Programmiereinsteiger. Man muss ein Interesse an Clean Code haben und auch schon diverse Regeln kennen und anwenden, LINQ darf kein Fremdwort mehr sein. Dann bietet NDepend eine sehr gute Untersützung. Wenn man für diesen Schritt bereit ist, bietet das Tool einen hervorragenden Start in die permanenten Prüfung und Überwachung von Code-Regeln, zumal sogar für die Integration in Buildserver gesorgt wurde. NDepend liefert ein umfangreiches Set an Regeln, sauber gruppiert, bereits mit. Eigene Regeln können aus dem Code extrahiert werden. Als absolutes Power-Feature bewerte ich die Definition einer Baseline für vergleichende Berichte. Damit können alte Probleme leichter ausgeblendet werden.

Eine Bewertung zum Preis fällt schwer: Die Dialog von NDepend wurden mit sehr viel Liebe erstellt. Praktisch überall stehen sinnvolle Optionen, Verknüpfungen zu Hilfethemen und Tooltips zur Verfügung. Der Preis erscheint hierfür eigentlich zu gering. Aus der Sicht der Programmierer, die bei Clean-Code oft nicht gerade offene Türen einrennen, ist der Preis dann wieder wirklich sinnvoll und mit Blick auf den Funktionsumfang mehr als fair.

KategorienCCD, Microsoft .NET Tags: ,

Probleme mit Visual Studio Formular Designer

11. Januar 2014 Keine Kommentare

Beim Öffnen großer Formulare in Visual Studio Formular Designer (WinForms) tritt teilweise das Problem auf, dass Visual Studio 2012/2013 wegen eines Problems beendet wird. In der Ereignisanzeige wird dabei ein Problem in der KERNELBASE.dll vermerkt.

Die Lösung ist dann eigentlich trivial: Es muss der Dienst Performance Logs & Alerts (pla) gestartet werden.

Es besteht nun die Vermutung, dass der Formulardesigner einfach eine Performance-Warnung melden wollte und das nicht konnte, weil der Dienst nicht aktiv war.

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: ,

.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: ,

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.

dotnet-snippets.de wird 5 Jahre alt

24. April 2011 Keine Kommentare

Die Webseite dotnet-snippets.de wird 5 Jahre alt. Herzlichen Glückwunsch!

Wer die Seite noch nicht kennt, aber mit Microsoft .NET entwickelt, sollte einfach mal vorbeischauen. Es gibt viele kurze hilfreiche Codeschnipsel zu den meisten Problemchen, die man so im täglichen Leben hat.

KategorienAllgemein, Microsoft .NET Tags:

Alte Daten mittels Powershell löschen

13. April 2011 1 Kommentar

In einem Backup-Ordner stand die Aufgabe an, alte Dateien automatisch löschen zu lassen. Dazu wurde folgendes Skript eingesetzt:

Get-ChildItem -Path . |
  Where-Object -FilterScript {($_.LastWriteTime -lt [DateTime]::Now.AddDays(-7))} |
  Remove-Item -force

Zuerst werden alle relevanten Dateien ermittelt. Danach wird auf diese Liste ein Filter gesetzt, der nur Dateien ermittelt, die älter als 7 Tage sind. Hierzu wird eine Rückgriff auf DateTime aus dem Net-Framework genutzt. Es bietet mit Now und AddDays die gewünschte Funktionalität, von jetzt 7 Tage nach hinten zu gehen. Als letzten Schritt muss die ermittelte Liste lediglich an Remove-Item weitergereicht werden.