Office oder Windows Lizenzschluessel aus einer anderen Windows Installation wiederherstellen
Die Beiträge hier im Blog darüber wie man den Office und Windows Key aus der Registry lesen kann erfreuen sich sich großer Beliebtheit, weswegen ich auch das kleine Tool Get My Keys Back erstellt habe.
Doch erreichen mich immer mehr Mails mit der Frage danach wie man den Schlüssel wiederherstellen kann wenn man Windows neuinstalliert hat, wenn die Installation beschädigt ist oder wenn die Daten auf einer anderen Festplatte liegen.
Manchmal passiert es auch, dass Get My Keys Back es nicht schafft den Office Key auszulesen, obwohl Office installiert ist. Mit dieser Anleitung könnt ihr es nun manuell machen.
Get My Keys Back funktioniert hier natürlich nicht, da es nur in der gerade aktiven Registry nach dem Schlüssel sucht. Ich habe mich mit dieser Frage etwas beschäftigt und hoffe euch mit diesem Beitrag eine Hilfestellung geben zu können.
SerialDecoder
Um es euch möglichst einfach zu machen habe ich das kleine Tool "SerialDecoder" geschrieben, das ihr ab sofort auf meiner Homepage herunterladen und testen könnt. Dieses Programm benötigt aber auch die Werte aus der Registry, und zwar aus der Registry die nicht mehr aktiv ist, z.B. die auf eurer anderen Festplatte von der ihr die Seriennummer haben wollt.
Der Prozess den Schlüssel zu beschaffen unterteilt sich in drei Schritte:
- Beschaffen der Registrydaten von der alten Festplatte
- Beschaffen der Daten aus der alten Registry
- Umwandeln der Daten in den schlüssel
An euch liegt es nun diese Daten aus der anderen Festplatte zu lesen. Dies ist relativ einfach, folgt einfach dieser kleinen Anleitung:
- Schließt die alte Festplatte an und öffnet diese im Windows Explorer
- Navigiert dort in das Verzeichnis: \Windows\System32\config
- Kopiert aus diesem Verzeichnis die Datei "SOFTWARE" in ein Verzeichnis auf eurer aktiven Festplatte.
- Startet nun die Registry, indem ihr die Windows-Taste und die R-Taste gleichzeitig drückt.
- In das nun erscheinende Fenster tippt ihr "regedit" ohne "" und drückt auf OK.
- Im Regestrierungseditor klickt ihr auf Datei und dann auf Struktur laden...
- Wählt nun die eben kopierte Datei "SOFTWARE" aus.
- Gebt nun einen schlüssigen Namen ein z.B. "Alte Festplatte"
- Nun wird diese Registry Datei geladen und ihr seht sie in eurem Registry-Explorer. Öffnet diese nun.
Schritt 2: Auslesen der Schlüssel
Navigiert in der nun geladenen Struktur an folgende Stellen um die Keys zu erhalten:
Office auf 32-Bit Systemen:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office
Office auf 64-Bit Systemen:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office
Bei Office wählt ihr nun eure Version, wobei
- 11 = 2003
- 12 = 2007
- 14 = 2010
Im Normalfall solltet ihr einfach die größte Zahl auswählen. In diesem Verzeichnis wählt ihr nun den Ordner Registration. Hier werden wahrscheinlich einige Ordner mit sehr kryptischen Namen sein, sucht den wo der Schlüssel namens "DigitalProduvtId" auftaucht:
Probiert die Ordner einfach durch, der richtige Ordner ist meist der mit den meisten Schlüsseln.
Klickt nun mit der rechten Maustaste auf den passenden Ordner und wählt "Exportieren". Speichert die Datei nun ab.
(Falls ihr nur diesen Key benötigt springt zum Schritt 3 Schlüssel umwandeln weiter unten)
Windows Key:
SOFTWARE\Microsoft\Windows NT\CurrentVersion
Hier seht ihr nun einige Schlüssel, unter Anderem auch den DigitalProductId, der uns interessiert (Beispiel für Windows Key).
Klickt nun mir der rechten Maustaste auf den Ordner "CurrentVersion" in der rechten Übersicht und wählt "Exportieren" und speichert die Daten an einem für euch leicht wieder findbaren Ort.
Schritt 3: Schlüssel umwandeln
Da ihr nun die Daten zum Windows und/oder zum Office Key gesichert habt könnt ihr diese nun nutzen um den Key wiederherzustellen.
Nun müsst ihr mein kleines Tool namens "SerialDecoder" von meiner Homepage laden und starten.
Öffnet nun eine der Dateien die ihr eben durch das Exportieren erstellt habt in einem Texteditor:
Sucht den Eintrag namens "DigitalProductId" und markiert alle Zeichen ab hex: bis zum Ende des Eintrags. Ein Beispiel wie es aussehen kann seht ihr in dem Oberen Bild. Wichtig: Markiert wirklich nur diesen Bereich ohne das hex: und ohne den Eigenschaften-Namen, wirklich genauso wie es oben in dem Bild gezeigt ist.
Das Bild zeigt ein Beispiel für einen Windows Key, die Office-Keys sind für gewöhnlich länger, lasst euch davon also nicht verwirren.
Kopiert diesen Markierten Text nun in die Zwischenablage und fügt diesen Text nun im SerialDecoder ein:
Nicht erschrecken: Der SerialDecoder entfernt alle unnötigen Zeichen wie Leerzeichen und Zeilenumbrüche.
Klickt nun auf "Schlüssel auslesen" unten im Fenster und wählt die Art von Schlüssel die ihr auslesen wollt. (Hier Windows Key)
Der SerialDecoder wandelt nun die Daten in euren Key um.
ACHTUNG: SerialDecoder kann nicht feststellen ob ihr die Daten korrekt eingefügt habt, also ob ihr vielleicht zuviel kopiert habt oder zu wenig. Deswegen achtet sehr genau was ihr reinkopiert! Des Weiteren kann ich natürlich nicht für die Korrektheit des ausgelesenen Keys garantieren. Das Programm ist grad in der Testphase und lebt momentan von eurem Feedback, damit ich es weiter verbessern kann.
GlassFish: Unnoetige HTTP-Response Header entfernen
In dem letzten Artikel habe ich beschrieben, wie ihr unter ASP.NET MVC Anwendungen die verräterischen HTTP Header ausblenden könnt, nun können wir auch mal auf den GlassFish schauen.
Wie ihr in dem oberen Bild erkennen könnt sendet der GlassFish hier seinen Namen, die Version und auch das verwendete Framework mit. Das wollen wir natürlich nicht haben.
Fangen wir mit dem Server-Header an. Dieser ist recht einfach zu entfernen durch das Setzen eines VM-Parameters in der GlassFish Adminoberfläche.
- Startet die Admin console
- Wählt Configuration ->JVM Settings
- Wählt oben JVM Options
- Klickst auf Add JVM Option
- In der neue textfeld tragt ihr ein: -Dproduct.name=""
- Klickt auf Save und startet den GlassFish neu
Auch wenn das nun etwas komisch aussieht, haben wir so den Server-Header entfernt. Dabei verhält sich der GlassFish unter verschiedenen Umständen anders. Manchmal zeigt er den Header so an wie in dem Bild, manchmal lässt er ihn auch komplett weg. (Wenn ihr hier mehr wisst hinterlasst bitte ein Kommentar).
X-Powered-By header
- Startet die Admin console
- Geht zu Configuration -> Network Config -> Network Listeners
- Wählt http-listener-2 aus und wählt dann oben "HTTP"
- Deaktiviert den Hacken bei "XPowered By" (Siehe Bild)
- Speichert und startet den GlassFish neu
Leider ist die Sache damit noch nicht gegessen, da dies scheinbar nur den "X-Powered-By: Servlet/3.0" Header entfernt den "X-Powered-By: JSP/2.1" muss man nochmal wo anders entfernen.
- Navigiert zu domains/domain1/config
- öffnet die Datei default-web.xml
- sucht nach xpoweredBy und setzt diesen Setting auf "false" (siehe Bild)
- Speichert und startet den GlassFish neu
Nun sieht die Sache wieder bessern aus:
Wenn ihr noch einen Tipp habt wie man den Server-Header ganz weg bekommt wäre ich für einen Kommentar dankbar!
ASP.NET MVC Security Teil 2: Unnoetige HTTP Response-Header entfernen
In dieser Reihe von Posts möchte ich Wege zum Absichern einer MVC Anwendung zeigen, die man gerne mal vergisst oder als Neueinsteiger nicht gleich auf dem Schirm hat.
Teil 2: Unnötige HTTP Response-Header entfernen
Wenn wir im Internet surfen werden oft Informationen über uns ohne unser Zutun bei jedem Request an den Server übertragen. Dies geschieht über die HTTP-Header. So wird z.B. die Adresse der Seite auf der wir einen Link geklickt haben in dem Referrer-Header an den Server übertragen.
Aber auch die Server selbst sind in dieser Sache oft sehr gesprächig und verraten mehr über sich als wirklich nötig ist.
In dem Bild sieht man (rot eingerahmt) Informationen die der Server über unsere Anwendung nach außen gibt, die eigentlich lieber geheim bleiben sollten.
Warum ist das gefährlich?
Die Informationen, die hier angezeigt werden verraten die Version des Servers, der Laufzeitumgebung und die Version des Frameworks, das wir benutzen. In diesem Fall ASP.NET MVC 3.
Falls nun bekannt wird, dass der Server oder ASP.NET in dieser Version eine Sicherheitslücke aufweist, sieht ein potentieller Angreifer sofort, dass unsere Seite für eine Attacke anfällig ist.
Es gibt sogar extra Tools, die das Web nach Webseiten durchsuchen, die eine Serverversion aufweisen, die als unsicher eingestuft wird oder für die es bekannte Lücken gibt. Diese Tools nutzen unter Anderem dann auch diese Informationen um zu prüfen ob es sich lohnt bei dieser Seite einen Angriff zu starten.
Was nun?
Im Grunde ist die Aufgabe sehr einfach, wir müssen diese unnötigen Serverheader ausblenden. Wenn die Webseite dann keine anderen Frameworkspezifischen Merkmale aufweist (wie z.B. einen Viewstate) ist es für einen Besucher praktisch unmöglich herauszufinden, welcher Server und welches Framework im Backend laufen.
Die Umsetzung
Leider ist ASP.NET in dieser Hinsicht noch nicht so richtig benutzerfreundlich, denn um all diese Header zu entfernen müssen wir an einigen verschiedenen Stellen Änderungen vornehmen. Gehen wir mal Schritt für Schritt alles durch.
1. ASP.NET & MVC Header
Diesen Header können wir recht einfach entfernen, indem wir in der global.asax die nötige Property setzen:
protected void Application_Start()
{
MvcHandler.DisableMvcResponseHeader = true; //<- Hier
AreaRegistration.RegisterAllAreas();
Database.SetInitializer(new F1DBInitializer());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
Dies hat schon eine Gute Wirkung auf unsere Response Header:
Die Version von ASP.NET und des MVC Frameworks wird nun nicht mehr angezeigt. Nun zu den anderen.
2. X-Powered-By Header
Um diesen Header zu entfernen müssen wir unsere web.config ergänzen (Quelle):
<?xml version="1.0"?>
<configuration>
<system.web>
<httpRuntime enableVersionHeader="false" />
...
</system.web>
<system.webServer>
...
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
...
</configuration>
Dann verabschiedet sich auch dieser Header.
3. Einer geht noch: Der Server-Header
Dies geht leider nicht so einfach durch das Setzen eines Configparameters, hier müssen wir selbst Hand anlegen und diesen Header aus der Response löschen. Dazu schreiben wir uns ein eigenes HttpModul (Quelle):
public class RemoveServerHeaderModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
public void Dispose()
{ }
void OnPreSendRequestHeaders(object sender, EventArgs e)
{
HttpContext.Current.Response.Headers.Remove("Server");
}
}
Anschließend müssen wir das neue Modul über die web.config registrieren (Quelle):
<?xml version="1.0"?>
<configuration>
...
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<add name="RemoveServerHeaderModule" type="SecurityTipp.RemoveServerHeaderModule"/>
</modules>
...
</system.webServer>
</configuration>
Das Ergebnis:
Nun haben wir unser Ziel erreicht und alle Plaudertaschen aus der Response entfernt
Weitergedacht
Hier könnte man nun ansetzen und sogar versuchen den potentiellen Angreifer in die Irre zu führen, indem man einen modifizierten Server-Header zurückgibt der auf eine Ganz andere Serversoftware verweist, Apache oder sowas
Das Schöne hierbei ist weiterhin, dass wir alle diese Änderungen innerhalb unserer App machen können und nicht im IIS rumfummeln müssen. Einerseits weil man da viel kaputtkonfigurieren kann, andererseits weil man nicht immer Zugriff auf den IIS hat, wenn man z.B. nur ein Webspace hat.
Diese Schritte sollten bei jeder Anwendung durchgeführt werden, egal ob MVC, ASP.NET oder PHP, gebt den Besuchern nicht mehr Informationen als sie unbedingt benötigen!
ASP.NET MVC Security Teil 1: Das AntiForgeryToken nutzen
In dieser Reihe von Posts möchte ich Wege zum Absichern einer MVC Anwendung zeigen, die man gerne mal vergisst oder als Neueinsteiger nicht gleich auf dem Schirm hat.
Teil 1: Nutzen des AntiForgeryToken bei POST Requests
POST Requests sind gefährlich, da diese im Normalfall dafür verwendet werden dem Server Informationen mitzuteilen. Die Informationen sollte man natürlich prüfen, auf Form und Inhalt, aber noch wichtiger ist es, zu wissen wer uns diese Daten sendet. (Cross-Site-Attacken verhindern)
Wie funktioniert das?
Mit dem AntiForgeryToken können wir an dieser Stelle sichergehen, dass nur Formulare am Server angenommen werden, die der Server selbst erzeugt hat.
Dabei erzeugt der Server beim Generieren des Formulars einen Token und speichert diesen in einem versteckten Input-Feld (__RequestVerificationToken), des Weiteren wird auch ein Cookie namens "__RequestVerificationToken" mit dem gleichen Token angelegt, sodass beim Absenden des Formulars sowohl der Cookie als auch das versteckte Feld wieder zurück an den Server übertragen wird.
Wenn der Server diesen Request empfängt prüft er diesen Token aus dem versteckten Feld gegen das Token aus dem Cookie. Gibt es hier keine Übereinstimmung wird der Request abgewiesen.
Wie wird das implementiert?
Als Erstes muss das Token in das Formular gesetzt werden und das Cookie erzeugt werden. Diese Aufgabe übernimmt für und der kleine Html-Helper aus MVC.
<div class="myForm">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<!-- REST DES FORMULARS -->
}
</div>
Das ging ja einfach, nun müssen wir dafür sorgen, dass dieses Token beim Verarbeiten des Requests auch geprüft wird.
[ValidateAntiForgeryToken]
public ActionResult UpdateStuff()
{
...
}
Mehr ist das nicht, ein einfaches Attribut genügt, und unsere MVC Anwendung ist mit nur zwei Zeilen sicherer geworden.
Wenn Ihr nun einen Blick in euer gerendertes Formular werft, werdet ihr etwas in der Art finden:
<input name="__RequestVerificationToken" type="hidden" value="4PhvBw7EO5I3O4zw2cdYkaEfSJycy1Ugi8AOT6glW6IqZNnVKXTzL52LgQGNMviOhYTxAOQH3iZRtehUoHKRprcHXa8YNel6RzVmKjGAEi0W0duRpnwJu9EpR7ybAoZX9yqeiP3Pyng/ma1t/k6QhM2bbcoBgkou5y0KXEj8Ut8=" />
Gibt es Einschränkungen?
- Da hier ein Cookie gesetzt wird müssen natürlich Cookies aktiviert sein da der Server sonst alle Requests abweisen wird.
- Das Ganze funktioniert nur mit POST Requests, was auch logisch ist, da GET Requests nur zum Abfragen von Informationen genutzt werden sollten.
Alternativen?
Wenn man keine Cookies nutzen will kann man ein ähnliches Verhalten hervorrufen, indem man prüft ob der eingehende Request ein Referrer-Header besitzt der auf unsere eigene Domain + URL verweist.
Dies ist natürlich nicht wirklich Sicher, da es leicht zu fälschen ist und außerdem haben manche Browser Anonymisierungsfunktionen die diese Header-Felder nicht mitsenden, also ist hier Vorsicht geboten.
Chart helper in ASP.NET MVC nutzen
Vor einer Weile habe ich ein kleines Tutorial geschrieben wie ihr das kostenlose MSChart Control benutzen könnt um euch hübsche Grafen zeichnen zu lassen.
ASP.NET MVC 3 bietet euch einen Helper der eine sehr ähnliche Funktionalität bietet und sehr einfach in eure MVC Anwendung zu integrieren ist.
Das Schöne ist, dass wenn ihr das aktuelle Visual Studio Tools update installiert habt, ihr diesen Helper bereits out of the box nutzen. Falls nicht könnt ihr es über das NuGet Paket bequem nachinstallieren.
Hier ein kleines Beispiel wie eine Action aussehen kann, die ein Chart erzeugen soll:
public ActionResult CreateChart()
{
Chart bytes = new Chart(width: 400, height: 200)
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
yValues: new[] { "12", "3", "23", "11" })
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
yValues: new[] { "13", "32", "23", "5" });
return File(bytes.GetBytes("png"), "image/png");
}
Wie man sieht wird hier nachdem das Chart erstellt wurde eine Grafik daraus gemacht und diese dann an die View zur Anzeige gesendet. Der Aufruf in der View ist dementsprechend simpel:
<img src="@Url.Action("CreateChart")" alt="Beschreibung" />
Was vielleicht nicht auf den ersten Blick ersichtlich ist, ist wie man eine legende zu dem Chart anzeigen lassen kann. Dazu muss jede "Serie" einen namen erhalten und zum Schluss kann man dann die "AddLegend()" Methode ohne Parameter aufrufen:
public ActionResult CreateChart()
{
Chart chart = new Chart(width: 400, height: 200)
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
name: "Serie 1",
yValues: new[] { "12", "3", "23", "11" })
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
name: "Serie 2",
yValues: new[] { "13", "32", "23", "5" });
chart.AddLegend();
return File(chart.GetBytes("png"), "image/png");
}
Noch etwas umständlicher wird es, wenn man nun die legende an eine andere Stelle setzen will, denn hier muss ein eigenes Theme her. Dieses sollte dann auch nur die Felder enthalten die man ändern will. Wenn man z.B. die legende unten angezeigt haben möchte kann man so vorgehen:
public ActionResult CreateChart()
{
string theme = @"<Chart BackColor=""WhiteSmoke"" >
<ChartAreas>
<ChartArea Name=""Default"" BackColor=""White"">
</ChartAreas>
<Legends>
<Legend _Template_=""All"" BackColor=""Transparent"" Font=""Trebuchet MS, 9pt"" IsTextAutoFit=""False"" Docking=""Bottom"" />
</Legends>
</Chart>";
Chart chart = new Chart(width: 400, height: 200, theme: theme)
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
name: "Serie 1",
yValues: new[] { "12", "3", "23", "11" })
.AddSeries(
chartType: "column",
xValue: new[] { "Wert1", "Wert2", "Wert3", "Wert4" },
name: "Serie 2",
yValues: new[] { "13", "32", "23", "5" });
chart.AddLegend();
return File(chart.GetBytes("png"), "image/png");
}
Man beachte hier dass dem Chart-Konstruktor ein weiterer Parameter "theme" übergeben wird.
Im Grunde wars das auch schon. An der Handhabung ändert sich nicht viel. Falls ihr euch irgendwo vertippt wird übrigens einfach kein Bild erzeugt, also vorsicht beim Tippen
GMail: Punkte im Benutzernamen werden ignoriert
Heute habe ich eine EMail bekommen, die ganz klar nicht an mich gerichtet war, denn ich kannte weder den Absender und auch der Betreff brachte nichts zum Klingeln.
Als guter Mensch der ich auch bin
wollte ich die Mail natürlich an den eigentlichen Empfänger weiterleiten, denn seine Adresse stand unten als Ausgabe eines HTML-Formulars in der Mail mit drin.
Als ich die Adresse gesehen habe wurde mir auch klar, warum die bei mir angekommen ist, denn diese war:
big.basti@gouglemail.com
Ich dachte die korrekte Adresse wäre big.basti@googlemail.com und habe die Mail auch mit einer kurzen Erklärung dorthin weitergeleitet. Zu meiner Überraschung landete diese mail prompt wieder in meinem Posteingang.
Was ist denn nun los?
Nun habe ich mal genauer hingeschaut:
Dann ist mir auch der kleine Hinweis im Bild aufgefallen. Anscheinend weiß Google schon dass diese Verwechselung häufiger passiert. und hinter dem Link der sich hinter "Learn more" verbirgt bringt dann auch Licht ins dunkle.
There are three common reasons why Gmail users think they're receiving someone else's mail. Please select the description that matches your situation below.
Your address is similar but has more or fewer dots (.) or different capitalization.
Sometimes you may receive a message sent to an address that looks like yours but has a different number or arrangement of periods. While we know it might be unnerving if you think someone else's mail is being routed to your account, don't worry: both of these addresses are yours.
Gmail doesn't recognize dots as characters within usernames, you can add or remove the dots from a Gmail address without changing the actual destination address; they'll all go to your inbox, and only yours. In short:
- homerjsimpson@gmail.com = hom.er.j.sim.ps.on@gmail.com
- homerjsimpson@gmail.com = HOMERJSIMPSON@gmail.com
- homerjsimpson@gmail.com = Homer.J.Simpson@gmail.com
All these addresses belong to the same person. You can see this if you try to sign in with your username, but adding or removing a dot from it. You'll still go to your account.
Nun machts auch Sinn. Aber im Hintergrund scheint noch viel mehr zu passieren, denn man kann auch ein paar Buchstaben drehen oder weglassen und die Mails kommen dann trotzdem immer noch an - zumindest ist mir das schon häufiger passiert.
Auf jeden Fall ist das gut zu wissen, denn beim ersten Mal verwirrt es einen schon ganz schön
TL;DR
Google ignoriert Punkte "." im Benutzernamen, daher kommt die Mail dennoch an.
ASP.NET: Verbindungsname LocalSqlServer wurde in der Anwendungskonfiguration nicht gefunden
Am Wochenende hatte ich einen interessanten Fehler in meiner ASP.NET MVC Anwendung. Dieser tauchte auf nachdem die Anwendung schon einige Wochen Problemlos lief. Es handelte sich um diesen Fehler:
Konfigurationsfehler
Beschreibung: Fehler beim Verarbeiten einer Konfigurationsdatei, die für diese Anforderung erforderlich ist. Überprüfen Sie die unten angegebenen Fehlerinformationen, und ändern Sie die Konfigurationsdatei entsprechend.
Parserfehlermeldung: Der Verbindungsname LocalSqlServer wurde in der Anwendungskonfiguration nicht gefunden, oder die Verbindungszeichenfolge war leer.
Das Problem ist hier, dass das ASP.NET Membership per Default in der root web.config so konfiguriert ist, dass es den Connectionstring "LocalSqlServer" nutzen soll. Dieser Connectionstring zeigt dann (meistens) auf eine SQL Datenbank die auf dem Hostingsystem (noch) nicht verfügbar ist. An dieser Stelle knallt es dann.
Die einfachste Lösung für dieses Problem ist es den Connectionstring neu zusetzen. Dazu entfernt man erst den Defaulteintrag und setzt den neuen dann auf eine gültige Datenbankverbindung:
<remove name="LocalSqlServer" /> <add name="LocalSqlServer" connectionString="[EUER CONNECTIONSTRING]" providerName="System.Data.SqlClient" />
Dies hat das Problem behoben, sodass die Anwendung wieder wie gewohnt lief.
Was mir noch ein wenig Kopfschmerzen bereitet, ist dass ich das ASP.NET Membership gar nicht nutze und auch keinen "LocalSqlServer" Connectionstring habe. Des Weiteren lief die Anwendung erst wochenlang und plötzlich kam dann dieser Fehler.
Wenn ihr diesen Fehler vielleicht schon kennt oder euch noch was dazu einfällt würde ich mich über einen Kommentar mit einem Tipp freuen.
Aktuelle Zeile bei Kommandozeilen Applikationen aktualisieren
Vielleicht ist euch das ja auch schon Mal passiert, ihr entwickelt eine Kommandozeilen-App und wollt die Aktuelle Zeile ändern. Ein Beispiel dafür wäre ein Fortschrittsbalken oder der beliebte Command-Line-Spinner ( bestehend aus den Zeichen /, -, \, |. Wenn diese nacheinander angezeigt werden sieht das so aus wie ein sich drehender Ast
Das Ganze kann in allen Kommandozeilenfenstern, egal ob Unix oder Windows implementiert werden. Der Schlüssel hierzu ist das Sonderzeichen \b - welches das Drücken der Backspace Taste simuliert. Ähnliche Vertreter sind \t für Tab und \n für Zeilenumbruch.
Solange ihr noch keinen Zeilenumbruch abgesetzt habt könnt ihr jede Ausgabe in der aktuellen Zeile widerrufen durch das ausgeben von \b dabei müsst ihr jedes Zeichen einzeln widerrufen. Wenn wir nun also unser Spinner-beispiel betrachten kann man das sehr einfach in .NET umsetzen:
static void Main(string[] args) {
string[] states = { "\\", "|", "/", "-" };
int cur_state = 0;
while (true) {
Thread.Sleep(100);
Console.Write("\b");
Console.Write(states[cur_state]);
cur_state++;
if (cur_state == 4) {
cur_state = 0;
}
}
}
Genauso einfach geht das Ganze dann auch in Java:
public static void Main(string[] args) {
string[] states = { "\\", "|", "/", "-" };
int cur_state = 0;
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {}
System.out.print("\b");
System.out.print(states[cur_state]);
cur_state++;
if (cur_state == 4) {
cur_state = 0;
}
}
}
Ist in jedem Fall ein nettes Gimmick
Beachten sollte man noch, dass man hier print() bzw. Write() benutzen muss und nicht println() oder WriteLine() da hier sonst automatisch ein \n mit an das Ende der Zeile gepackt wird!
ASP.NET MVC: HTML5 Elemente mit jQuery Fallback nutzen
Soo, nachdem ich die Überschrift mit all den hippen Begriffen vollgepackt habe die es in Sachen Web momentan so gibt möchte ich euch kurz erklären worum es in diesem Artikel gehen soll.
Ihr werdet sicher mitbekommen haben, dass HTML5 auf dem Vormarsch ist und auch wenn es immer noch nicht offiziell fertig ist findet man immer häufiger den HTML5-Header <!DOCTYPE html> auf diversen Seiten.
Eins der meiner Meinung nach nützlichsten Features die wir mit HTML5 erhalten sind die neuen Input-Typen. Denn bisher hatten wir keine Wahl und mussten type="text" benutzen!
Die Eingabefelder vom Typ Text konnten natürlich alles enthalten, sind aber nicht gerade Benutzerfreundlich wenn man etwas komplexere Daten eingeben soll wie zum Beispiel ein Datum.
In HTML5 wurden deswegen spezifische Typen für solche immer wieder einkehrende Eingaben eingeführt. Eine von ihnen ist "Date":
Birthday: <input type="date" name="bday" />
Der große Vorteil hier ist, dass die Browser nun eine eigene Implementierung für diesen Typ von Eingabefeldern machen können. Falls der Browser nun also diesen neuen Eingabe Typ unterstützt blendet er automatisch einem (mehr oder weniger) schönen Date-Picker ein in dem man bequem das Datum wählen kann:
Ein weiterer großer Vorteil ist, dass auch die mobilen Browser wie z.B. auf dem iPhone diese neuen Elemente ebenfalls unterstützen und einen passenden Picker einblenden:
Wie ihr in dem ersten Screenshot sehen könnt unterstützt der FireFox (zumindest zum Zeitpunkt des Screenshots) den neuen Typ nicht. In diesem Fall blendet er ein gewöhnliches Textfeld ein wo wir nun gezwungen sind das Datum auf die gewohnte (unbequeme) Weise einzutragen.
Übrigens, ich glaube ich muss euch nicht sagen warum der Internet Explorer hier nicht mit aufgeführt ist oder?
Und genau das ist das Problem um das es in diesem Blogpost geht. Wenn wir die tollen neuen Elemente nutzen gehen wir das Risiko ein, dass Nutzer die einen älteren Browser nutzen nicht in den Genuss einer bequemen Eingabe kommen.
Wir könnten auch komplett auf das HTML5 Element verzichten und direkt alles mit jQuery machen, welches auch einen Date-Picker bietet, aber das ist auch nicht das gelbe vom Ei, denn dann wären die Mobilen Nutzer in Nachteil, da dort die Browser diese Elemente für gewöhnlich unterstützen und eine gewohnte Oberfläche für die Eingabe bieten.
Die Optimale Lösung ist offensichtlich eine Mischung beider Welten. Wenn der Benutzer die Seite mit einem kompatiblen Browser aufruft soll der Date-Picker des Browsers genutzt werden, wenn der Browser aber veraltet ist soll stattdessen der jQuery Fallback greifen und der JavaScript Date-Picker (siehe links) genutzt werden.
Zu unserem Glück macht uns ASP.NET MVC die Umsetzung dieses Plans sehr leicht, da es an den nötigen Stellen sehr einfach erweitert werden kann.
Schauen wir uns mal ein kleines Beispiel an. Wir haben eine Klasse Person, und wollen auch dessen Geburtstag speichern, hier wollen wir die tolle neue Funktionalität nutzen. Implementieren wir das Ganze jedoch erstmal wie gewohnt:
public class Person
{
public int ID { get; set; }
public String Name { get; set; }
public DateTime Geburtstag { get; set; }
}
Wenn wir die Model-Klasse haben können wir das MVC Scaffolding nutzen um für uns eine View zum Erstellen neuer Personen anzulegen:
Schauen wir uns nun doch mal an was da für uns tolles generiert wurde:
<div class="editor-field">
@Html.EditorFor(model => model.Geburtstag)
@Html.ValidationMessageFor(model => model.Geburtstag)
</div>
Auffällig hierbei ist, dass hier @Html.EditorFor genutzt wird und nicht etwa @Html.TextBoxFor! Der Hintergrund ist der, dass MVC bei der Generierung versuchen wird ein passendes Element für den angegebenen Datentyp (DateTime) zu bestimmen, aber da MVC standardmäßig nur den Typ Text kennt wird hier eigentlich immer ein Input-Element vom Typ text generiert.
Hier kommt uns die Erweiterbarkeit von MVC zu gute, denn wir können ganz einfach NuGet nutzen um uns die nötige Funktionalität zu verschaffen. Wir installieren das Packet MvcHtml5Templates.
Nachdem NuGet alles erledigt hat werdet ihr feststellen, dass ihr ein paar neue Dateien in eurem Views/Shared Verzeichnis habt (siehe Bild links). Und wie ihr schon an dem Namen erkennen könnt sind das die neuen Input-Typen aus HTML5.
Diese Templates machen im Grunde nichts anderes als die MVC-Eigenen zu überschreiben und versehen die mit dem passendem Type-Attribut.
Hier sind euch keine Grenzen gesetzt ihr könnt natürlich auch eire eigenen Templates definieren mit euren eigenen Typen. (Auch wenn man das eher selten benötigt)
Das Tolle: mehr müssen wir nicht machen. MVC wird nun zur Laufzeit statt einem Text ein Date Input-Element für uns anlegen. Beachtet, dass das nur geht wenn wir in der View die allgemeine Funktion @Html.EditorFor nutzen und keinen Spezifischen Typ angeben.
Schauen wir mal in den Sourcecode der zur Laufzeit für das Geburtstagsfeld generiert wird:
<input class="text-box single-line" data-val="true" data-val-required="Das Feld 'Geburtstag' ist erforderlich" id="Geburtstag" name="Geburtstag" type="datetime" value=""; />
Wie ihr seht wird nun der Korrekte Typ, nämlich datetime verwendet. Wenn wir die Seite nun also mit einem kompatiblen Browser aufrufen können wir ganz bequem das Datum wählen.
Leider ist der Opera Browser momentan wohl der einzige Desktop Browser der uns hier einen Benutzerfreundlichen Dialog einblendet (siehe erstes Bild oben), somit müssen wir dafür sorgen, dass die Benutzer mit anderen oder alten Browsern nicht benachteiligt werden.
Auch für diese Problematik bringt MVC bereits alles mit was nötig ist sie zu lösen. Werfen wir doch mal einen Blick in unseren Scripts Ordner finden wir alle nötigen jQuery und jQuery UI Skripte, dazu kommt noch die modernizr Bibliothek die uns auch zu Gute kommen wird.
Die jQuery Bibliotheken liefern und die nötige Funktionalität die wir benötigen um diesen hübschen Date-Picker einzublenden.
Die modernizr Bibliothek dagegen hilft uns herauszufinden ob der Browser, den der Benutzer momentan verwendet die gewünschten HTML5 Features unterstützt.
Nun müssen wir also bei unseren Formularen prüfen, ob der Browser die nötigen Funktionen kennt und bei Bedarf die jQuery Klassen einbinden. Das Ganze ist dank der Einfachheit von Modernizr und jQuery ziemlich simpel.
Wechseln wir zu unserer View und fügen die Referenzen auf die nötigen Skripte und CSS Dateien ein:
<script src="@Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/modernizr-1.7.js")" type="text/javascript"></script>
<link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
Unten in der View fügen wir nun eine Modernizr Abfrage ein und prüfen, ob der Browser das DateTime-Feld unterstützt, und wenn nicht lassen wir jQuery das Ganze für uns regeln:
<script type="text/javascript">
$(function () {
if (!Modernizr.inputtypes.date) {
$("input[type='datetime']").datepicker();
}
});
</script>
Mit dem Befehl $("input[type='datetime']").datepicker(); werden alle Input-Felder vom Typ DateTime durch den jQuery Picker ersetzt. Coole Sache!
Kleiner Hinweis am Rande: Das ist nicht wirklich best practice da die Skripte auch geladen werden wenn sie gar nicht benötigt werden (der Browser kennt das HTML5 Feld) ich habe das hier der Einfachheit geopfert.
Und das wars auch schon! Alle Browser die das Feld unterstützen blenden nun ihren Picker ein, ansonsten wird der jQuery Fallback genutzt.
Wir müssen uns auch nicht mit irgendwelchen UserAgent-Prüfungen herumschlagen und lassen das alles Modernizr erledigen, der das intern über JavaScript prüft und somit immer aktuell ist. Das heißt dass wenn irgendwann der IE plötzlich die neuen Typen kennt werden diese auch funktionieren!
Genauso könnt ihr auch bei all den anderen neuen HTML5 Typen vorgehen und euren Usern ein bestmögliches Bedienerlebnis bereiten
Konsolenausgaben in einer WindowsForms Applikation
Manchmal will man eine WindowsForms Anwendung auch über die Konsole aufrufen und dann möchte man natürlich auch Ausgaben der Anwendung in dem Konsolenfesnter sehen. Doch leider ist das nicht so einfach, da alle Aufrufe über die Console-Klasse werden ignoriert.
Doch warum ist das so? Das ist ganz einfach und liegt daran, dass das Konsolenfenster, das unser Programm startet zu einem anderem Prozess gehört, nämlich cmd.exe und somit nicht verbunden ist.
Was wir also tun müssen ist, unsere Ausgabe an das Konsolenfenster zu heften, das unsere Anwendung gestartet hat. Dafür kann man die Win32-Methode AttachConsole nutzen.
Diese ist sehr einfach aufgebaut und sollte vor der ersten Ausgabe an die Konsole aufgerufen werden:
Definition des Win32-Aufrufs: (Beispiele in VB.NET)
<DllImport("kernel32.dll")> _
Private Shared Function AttachConsole(dwProcessId As Integer) As Boolean
End Function
Um die Ausgabe an den Prozess zu geben der uns aufgerufen hat (Parent-Process) kann man hier als Wert -1 übergeben:
Private Const ATTACH_PARENT_PROCESS As Integer = -1
Was nun noch bleibt ist es die Methode aufzurufen, zum Beispiel in der Main-Methode der Applikation:
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AttachConsole(ATTACH_PARENT_PROCESS)
//[...]
Das wars auch schon, nun werden eure Ausgaben an das Konsolenfester umgeleitet. Um die Konsole wieder von eurem Prozess zu lösen kann die paremeterlose Methode FreeConsole genutzt werden.
Es lohnt sich hier natürlich dann auch eine Unterscheidung zu machen wie die App gestartet wurde, also ob über Konsole oder über Doppelklick wie immer. Wenn sie über die Konsole gestartet wird, sollte man vielleicht die Oberfläche nicht mehr anzeigen. Das kann man dann zB. daran erkennen, dass Environment.GetCommandLineArgs.Length > 1 ist.
Probleme
Leider gibts ein paar Nebeneffekte die nicht unbeachtlich sind.
Ein Problem ist, dass Konsolenfuntionen die die Ausgabe von Programmen umleiten zB. so: "myapp.exe -test >test.txt" nicht funktionieren, die Ausgabe erfolgt weiterhin auf der Konsole. Hierfür konnte ich leider keine Lösung finden, wenn euch was einfällt einfach kommentieren.
Das zweite ist nur eine Schönheitssache, nämlich wenn das Programm beendet wird wird erst nicht die gewohnte Konsoleneingabezeile angezeigt, sondern nur der blinkende Cursor, so dass es aussieht als ob das Programm noch laufen würde, was es aber nicht mehr tut. (Wie gesagt Schönheitssache) Das kann man zB. dadurch umgehen, dass man vor dem Beenden des Programms noch ein [Enter] auf der Konsole ausgibt.
Weitere Infos und auch eine kleine Diskussion gibts hier und hier.

























