Artikel: Steuerelemente für jeden Zweck
30.06.2008 21:18:16
|
Norbert Eder

In der aktuellen Ausgabe der
visual studio one wurde mein Artikel
Steuerelemente für jeden Zweck veröffentlicht.
Die Idee der Steuerelemente ist ja nicht neu. Relativ neu hingegen ist die Möglichkeit, grafische Elemente komplett von der eigentlichen Logik zu trennen zumindest gilt dies für Microsoft-basierte Technologien.Mit der Windows Presentation Foundation wird den Entwicklern genau dies in die Hand gelegt. Sie als Entwickler und auch Ihr Kunde können davon profitieren. Dieser Artikel zeigt Ihnen, wie Sie dynamische WPF-Steuerelemente selber bauen können.
Link:
visual studio one
Upgrade but don't upgrade
30.06.2008 13:03:47
|
Jens Häupel
Stellen Sie sich vor, Sie haben ein VSTO 2005 SE Projekt mit Visual Studio 2005 und wollen auf Visual Studio 2008 umsteigen. Das Projekt stellt eine Erweiterung für Office 2003 dar, Sie haben auf der Entwicklermaschine aber schon Office 2007 installiert. Wenn Sie dieses Projekt nun in VS 2008 öffnen, bekommen Sie zwar die neue Code Basis, aber das Add-In zielt nun auf Office 2007 und nicht mehr auf 2003. Wollten Sie das so? Wenn ja, fein - wenn nicht, dann kannten Sie die folgende Option nicht.
In den Optionen von VS 2008 findet sich eine Rubrik Office Tools, die genau dieses Verhalten steuern kann. Wie im Bild zu sehen, kann das Verhalten bei Projektupdates beeinflußt werden:
Damit kann nach wie vor gegen die gleiche Version von Office entwickelt werden, obwohl diese gar nicht mehr installiert ist.
Anthony Crider, Software Design Engineer im BizApps Team, hat darüber einen Blogeintrag geschrieben.
Übrigens kann man so auch ein neues Projekt für eine auf der Entwicklungsmaschine nicht vorhandene Office-Version anlegen. Das Deaktivieren der o.g. Option verhindert, daß beim nächsten Öffnen das Projekt auf die neue Office-Version konvertiert wird.
P/Invoke Interop Assistant
29.06.2008 15:34:00
|
Klaus Bock
Wer des öfteren Gebrauch von P/Invoke macht hat sich bestimmt schon das ein oder andere mal ein Werkzeug gewünscht, welches die diversen Typen, Konstanten und Prozeduren der win32-API zeigt. Bislang gab es eigentlich nur die Seite PInvoke.NET sowie deren Visual Studio Add-In. Da es aber genug Leute gibt die nur die Visual Studio Express Editions verwenden, welche ja bekanntlich keine Add-In's erlauben, blieb bis Dato nur die Seite PInvoke.NET oder eben die mühsame Suche im Internet.
Mit dem P/Invoke Interop Assistant hat nun Microsoft ein genau solches Werkzeug auf CodePlex zur Verfügung gestellt. Der Toolkit beinhaltet die Konsolenanwendungen sigimp.exe zur Konvertierung von nicht verwalteten in verwalteten Code und sigexp.exe zur Konvertierung von verwalteten in nicht verwalteten C Code. Die interessanteste Anwendung dürfte jedoch die GUI-Anwendung winsiggen.exe sein. Sie zeigt im Reiter SigImpSearch die verschiedenen win32-API Prozeduren, Typen und Strukturen in einer Tabelle an. In einer DDL kann die Auswahl auf einen bestimmten Typ, z.B.: Prozeduren, eingeschränkt werden. Wer den Namen der Prozedur kennt, kann in der Textbox Name den Namen eingeben. Während der Eingabe wird die Auswahl in der Tabelle bereits verfeinert. Jetzt braucht nur noch die benötigte Prozedur ausgewählt zu werden und mit einem Klick auf die Schaltfläche Generate wird im rechten Code-Fenster eine komplette Klasse NativeMethods sowie evtl. benötigte Strukturen in der ausgewählten Sprache erzeugt. Per copy paste braucht der erzeugte Code nun nur noch in eine Klassen-Datei eingefügt zu werden und die Arbeit ist getan. Beim erzeugen des verwalteten Code werden auch gleich die passenden InAttribute und OutAttribute gesetzt. Das Marshalling in den entsprechenden unmanaged Typ wird ebenfalls vom P/Invoke Interop Assistant übernommen.

Einfacher geht es wirklich nicht, oder?
Die beiden Entwickler des P/Invove Interop Assistant, Yi Zhang und Xiaoying Guo, haben im MSDN Magazin einen sehr guten Artikel zum Marshalling zwischen verwaltetem und nicht verwaltetem Code veröffentlicht. Dieser Artikel zeigt auf verständliche Art die Grundlagen des Marshalling und stellt somit einiges an Hintergrundinformationen zum P/Invoke Interop Assistant zur Verfügung.
Was ich mir in der Anwendung noch wünschen würde ist zum einen: eine Verknüpfung zur Dokumentation der jeweiligen Funktion in der MSDN; und zum anderen eine einfache Möglichkeit die vorhandene windows.xml, die als Datenbasis für die win32-API verwendet wird, um eigene oder nicht beachtete Einträge zu erweitern.
Technorati-Tags:
PInvoke |
COM Interop
Formatierung aus Zwischenablage entfernen
29.06.2008 15:15:06
|
Jan Welker
Text, der aus dem Visual Studio Editor oder aus Word herauskopiert wird, wird mit
Formatierung in die Zwischenablage eingefügt.
Fügt man diesen Text in Web-Editoren (z.B. FreeTextBox) ein, gibt es häufig Probleme
mit dieser Formatierung.
Um das Problem zu umgehen, habe ich bisher den Text in Notepad kopiert um die Formatierung
zu entfernen.
Heute bin ich auch ein kleines Tool gestoßen, dass diesen Arbeitsschritt überflüssig
macht: PureText.
Diese kleine Anwendung kann beim Windowsstart mit geladen werden. Sobald das PT Logo
in der Taskleiste einmal angeklickt wird, werden alle Formatierungen des Textes aus
der Zwischenablage entfernt, wirklich praktisch.
Download unter: http://www.stevemiller.net/puretext/
Eine Liste von Strings (Oder andere Objekte ohne Eigenschaften) an ein Control binden
29.06.2008 04:56:00
|
Peter Bucher
Objekte bspw. an einen Repeater zu binden ist relativ einfach, die Eval()-Methode benötigt einen String-Parameter der die Eigenschaft des Objektes darstellt.
Eine Liste (oder Array) von Strings hat jedoch keine schlaue Eigenschaft, <String>.Length bringt auch nicht das gewünschte.
Es funktioniert aber mit einem simplen Kommando:
List<string> list = new List<string>();
list.Add("Lorem");
list.Add("Ipsum");
rptTest.DataSource = list;
rptTest.DataBind();
(ASPX Code im Repeater ItemTemplate)
<ItemTemplate>
<%# Container.DataItem %><br />
</ItemTemplate>
Update:
Das ganze funktioniert natürlich mit allen Objekten, die keine Eigenschaften haben.
Bspw. mit einem Objekt-Array:
object[] arr = new object[] {
"Lorem",
"Impsum",
"Dorem"
};
rptTest.DataSource = arr;
rptTest.DataBind();
Das ist alles, somit wird der aktuelle String in der Liste dargestellt.
Subversion 1.5 released
28.06.2008 09:49:45
|
Andre Loker
OK, it has already been some days since release, nevertheless you might not have noticed. Subversion 1.5 has been released, bringing some improvements and changes. As a consequence, I spent 30 minutes today upgrading the tools related to SVN:
Be aware that repositories and working directories that have been upgraded to the new 1.5 format are not compatible with subversion 1.4.x and below. Furthermore, the working directory upgrade occurs automatically(!) if you use a svn 1.5 on a working dir. Repository upgrades don't happen automatically, though, and must be triggered with svnadmin upgrade or simply using VisualSVN Server (right mouse click on the Repositories node, "All tasks => Upgrade Repositories format...").
Einführung in Linq to XML
28.06.2008 00:11:28
|
Jan Welker
Post-Redirect-Get
27.06.2008 17:01:26
|
Andre Loker
HTTP methods
As you probably know, HTTP supports several methods that define the nature of the current request. The two most important ones are GET and POST. GET is the primary method to get content (so called entities) from the server such as HTML pages, images, CSS style sheets etc. The POST method on the other hand is meant to transport entities to the server, for example login credentials or a blog comment. On the server side a POST request often results in an update of certain data (databases, session state).
Both GET and POST can return an entity as a response. For GET this is obvious - it's what the method exists for in the first place. For POST it might sound reasonable in the first place as well, but it brings a pile of problems.
A simple scenario
Imagine you fill in a sign-up form of some web based e-mail service and POST it to the server using a submit button. The server processes the new account and updates its database. Maybe it even logs you in directly. In response of the POST request the server directly shows you a view of your inbox. Here's a diagram of what happens between browser and server:
- The browser POSTs form data to an URL called signup.aspx
- The server processes the request
- The server responds with a status code of 200 (OK) and sends back a view of the new users inbox rendered as HTML
You leave the computer to have a coffee and when you come back 5 minutes later you refresh the page (using CTRL+R or F5 or whatever shortcut your browser uses) to see whether you already have new messages. You are a bit puzzled why this (or a similar) message box appears:
You click on OK and are even more confused as the page that appears says "This user name is already taken" instead of showing your inbox .
What has happened? Remember that the page you saw was the response of a POST request (submitting the sign up form). When you refreshed the page and confirmed to "resend the data" you actually repeated the POST request with the same form data. The server processed the "new" account and found that the user name is already in use (by yourself!), therefore it showed an error. "But wait", you say, "I just wanted the server to refresh the view of my inbox, what have I done wrong? " The answer is: nothing! The problem is that the application abused the POST response to transport an entity back to the client that should have been accessed with a GET request in the first place.
POST related issues
Here are some of the problems that occur if you abuse POST requests to return entities:
1. Refreshing the page results in a re-transmission of the POST data
This is what I described above. Hitting "refresh page" for a reponse based on a POST request will re-issue the POST request. Instead of refreshing what you see this will repeat what you did to reach the current page. This is not "refresh page" anymore, it becomes "repeat last action" - which is most likely not what the user wants. If you see a summary page after you have submitted an order in an online store, you don't want F5 to drop another order, do you?
2. POST responses are hard to bookmark
Bookmarks (or favourites etc.) normally only remember the URL of the bookmarked page (along with some user supplied meta data). Because a POST request transports data in the request body instead as query parameters in the URL like GET does, bookmarking the result of a POST will not work in most cases.
3. POST responses pollute the browser history
If the browser keeps the result of a POST request in it's history, going back to that history entry will normally result in POST data to be retransmitted. This again causes the same issues as mentioned in point 1.
POST-Redirect-GET
"But I need POSTs to send forms to the server - how can I avoid the problems mentioned above?" you might say. Here's where the POST-Redirect-GET (PRG hereafter) pattern enters the stage.
Instead of sending entity content with the POST response after we processed the request, we return the URL of a new location which the browser should visit afterwards. Normally this new location shows the result of the POST or an updated view of some domain model.
This can be achieved by not returning a result code of 200 (success) but instead returning a status code that indicates a new location for the result, for example 303 ("See other") or 302("Found"/"Moved temporarily"), the latter of which is used most often nowadays. Together with the 30x result code a Location header is sent which contains the URL of the page to which the request is redirected. Only the headers are sent, no body is included.
If the browser sees the 30x status code, it will look for the Location header and issue a GET request to the URL mentioned there. Finally the user will see the body of that GET request in the browser.
The browser-server communication would look like this:
- The browser POSTs to signup.aspx
- The server updates some state etc.
- The response is 302 redirect with a Location header value of inbox.aspx
- The browser realizes that the response is redirected and issues a GET to inbox.aspx
- The server returns 200 together with the content of the resource.
What do we gain?
- The page can be safely refreshed. Refreshing will cause another GET to inbox.aspx which won't cause any updates on the server
- The result page can be easily bookmarked. Because the current resource is defined by the URL a bookmark to this URL is likely to be valid.
- The browser history stays clean. Responses that have a redirect status code (such as 302) will not be put into the browser cache by most browsers. Only the location to which the response is redirecting is. Therefore signup.aspx won't be added to the history and we can safely go back and forth through the history without having to resubmit any POST data
The drawbacks of POST-Redirect-GET
While it should be clear by now that the POST-Redirect-GET pattern is the way to go in most situations, I'd like to point at the few drawbacks that come along with this pattern.
First of all, redirection from one request to another causes an extra roundtrip to the server (one for the POST request, one for the GET request it redirects to). In this context the roundtrip should be understood as all processing and transmission time that is required and fixed per request, ie. transmission delay, creation and invation of the HTTP handler, opening and closing database connections/transactions, filling ORM caches etc.
If both requests can be handled very quickly by the server this will essentially double the response time. If your roundtrip time is 200ms, using PRG will cause a minimum delay of 400ms between submitting the form and the result page being visible. This issues has to be put in perspective with reality, however. The server will need some time processing both requests, so the percentage of time needed for the roundtrips decreases with the amount of time server processing time takes. The response from the POST itself can be extremely small (few hundred bytes), because only the headers need to be transmitted.
In practice I haven't noticed a real performance problem with PRG. A slow app will stay slow, a fast one won't truly suffer from the extra roundtrip. And besides, if you replace POSTs by GETs where appropriate the effect of PRG will be even less noticeable.
The problem with ASP.NET WebForms
Now that you know about POST-Redirect-GET you are of course eager to use it (at least I hope I could convince you). But as an ASP.NET WebForms developer you will soon run into problems: ASP.NET WebForms is fundamentally based on POSTs to the server. In essence, all ASP.NET web pages are wrapped in one huge <form> element with "method" set to "POST". Whenever you click a button, you essentially POST all form fields to the server. Of course you can redirect from a Button.Click handler. If you do so, you're applying PRG. At the same time you're working quite against the WebForms philosophy, especially the ViewState (which will get lost as soon as you redirect), which will force you to rethink a lot of your application logic. And if you don't rely on all this postback behaviour inherent to ASP.NET WebForms you might as well ask why you're using WebForms in the first place.
This makes clear why a lot of developers (including me) think that WebForms are inherently "broken" (viewstate, ubiquitous postbacks and the hard-to-mock HttpContext are just a few reasons). If you share these concerns but like .NET just as I do, you might want to look at alternate .NET based web frameworks such as Castle MonoRail or ASP.NET MVC.
PRG and AJAX
In situations where you use AJAX the whole PRG issue becomes a new story. AJAX responses don't appear in the history, you wouldn't want to bookmark them and refreshing a web page does not re-issue any AJAX requests (except those fired on page load). Therefore I have no problem with returning entitiest (HTML fragments, JSON, XML) from AJAX POSTs - PRG is not of much use here.
Conclusion
To conclude this article here's a list of some basic rules that have been useful to me:
- Use POST-Redirect-GET whenever you can, that is: whenever you process a POST request on the server, send a redirect to a GETtable resource as response. It's applicable in almost all cases and will make your site much more usable for the visitor
- Don't POST what you can GET. If you only want to retrieve a parameterised resource it might be completely suitable to use a GET request with query string parameters. Google is a good example. The start page contains a simple form with a single text field to enter the search terms. Submitting the form causes a GET to /search with the search terms passed as the query string parameter q. This can be easily done by providing method="GET" on the <form> element (or just leave out the method attribute, as GET is the default).
- POST requests from AJAX are allowed to return entities directly as they don't suffer from the problems like "full" POSTs.
Support aus einer etwas anderen Richtung :-)
26.06.2008 21:27:50
|
Oliver Scheer
Deutsche Silverlight Webcasts verfügbar
26.06.2008 21:18:40
|
Oliver Scheer
Pfade - relativ / absolut / Root Operator, etc...
26.06.2008 17:59:00
|
Peter Bucher
Gerade bei Neueinsteigern in der Webentwicklung gibt es oft Verwirrung bei den Pfadangaben.
Die folgenden Links sollen bei Begriffen wie: Root Operator, relativ, absolut, etc... ein wenig Klarheit schaffen.
[MSDN: ASP.NET-Webseitenpfade]
[SelfHtml: Referenzieren in Html]
[SelfHtml: Basis (base-Tag)]
UniformGrid - das einfache Grid
24.06.2008 22:49:37
|
Norbert Eder
Im Namespace
System.Windows.Controls.Primitives verbirgt sich ein Grid namens
UniformGrid. Dabei handelt es sich um ein wirklich sehr einfaches Grid, welches (wie der Name schon sagt) im Endeffekt nicht mehr tut, als alle enthaltenen Elemente in gleicher Größe darzustellen. Dabei wandert jedes Kindelement in eine eigene Zelle.
Sehen wir uns gleichein Beispiel an:
<UniformGrid>
<Button Content="Button 1"/>
<Button Content="Button 2"/>
<Button Content="Button 3"/>
<Button Content="Button 4"/>
</UniformGrid>
Definiert wird ein UniformGrid mit insgesamt vier Buttons als Kindelemente. Und so sieht's aus:
Wird nun ein weiterer Button hinzugefügt, ändert sich das UniformGrid wie folgt:
Wie also zu sehen ist, werden die notwendigen Spalten und Reihen automatisch berechnet. Diese können aber mit den Attributen
Columns und
Rows beeinflusst werden:
<UniformGrid Columns="2" Rows="3">
<Button Content="Button 1"/>
<Button Content="Button 2"/>
<Button Content="Button 3"/>
<Button Content="Button 4"/>
<Button Content="Button 5"/>
</UniformGrid>
Definiert sind zwei Spalten und drei Reihen. Hier das Ergebnis:
Aber
aufgepasst: angezeigt wird nur, was auch tatsächlich auf die vorhandene Fläche passt:
<UniformGrid Columns="2" Rows="2">
<Button Content="Button 1"/>
<Button Content="Button 2"/>
<Button Content="Button 3"/>
<Button Content="Button 4"/>
<Button Content="Button 5"/>
</UniformGrid>
Definiert sind zwei Spalten und zwei Reihen, vorhanden sind jedoch fünf Elemente. Das wird daraus:
Viel Spaß beim Probieren.
Buchempfehlung: Test-Driven-Development. By Example.
24.06.2008 20:39:55
|
Robert Mühsig
Wer einen netten Einstieg in die “TDD-Welt” wagen möchte, dem empfehle ich das Buch “Test-Driven-Development. By Example” von Kent Beck.
In diesem Buch wird an 2 Beispielen TDD “in der Praxis” gezeigt.
Das erste Beispiel ist in Java geschrieben, dabei dreht es sich um ein Finanzbeispiel um verschiedene Währungen miteinander zu addieren etc.
Im Laufe des Beispieles werden verschiedene Techniken gezeigt und der Code entsteht nach und nach.
Im zweiten Beispiel wird mit Phyton das xUnit Beispiel gezeigt. Dabei geht es darum, ein eigenes Test-Framework zu erstellen.
Die “zweite” Hälfte des Buches ist dann mit Patterns, Vorgehensweisen etc. gefüllt - sodass man ein guten Einstieg erlebt.
Mir hat bei dem Beispielen manchmal etwas der Überblick gefehlt, zudem ist das englisch an machen stellen etwas anspruchsvoller (allerdings ist es eine recht lockere Schreibweise und angenehm zu lesen
).
Fazit: Empfehlenswert - und für 20 Euro auch nicht zu teuer
Amazon.de Widgets
ShareThis
Was hat Firefox 3 mit Nirvana zu tun?
24.06.2008 15:49:43
|
Norbert Eder
Gemeint ist hier nicht
Nirvana als Band, sondern vielmehr
Nirwana als Austritt aus dem Kreislauf des Leidens.
Aber was hat das nun mit Firefox 3 zu tun? Grundsätzlich ja ein Browser, den ich dann doch des Öfteren benutze, da ich auf einem Rechner IE7 nicht installieren kann, da sonst ein bestimmtes Produkt nicht laufen würde und da hin und wieder Webgeschichten mit mehreren Browsern getestet werden müssen.
Nun allerdings seit Firefox 3 bin ich mir nicht mehr so sicher, ob ich ihn auch wirklich weiterhin benutzen möchte. Ich tippe mal auf: "Nein, ich will nicht". Warum? Weil sich Firefox 3 gerade bei Multimedia-Inhalten von seinem Leid selbständig erlöst und einfach alle Schotten dicht macht. Bumm, zack und weg. Ständig.
Ab sofort kann sich das Teil im Nirwana vertschüssen, so oft es will. Da stört es mich nicht weiter. *Winke*
HowTo: Membership in Klassenbibliotheken / DLLs
23.06.2008 23:09:36
|
Robert Mühsig
In diesem HowTo habe ich das ASP.NET Membership System mal kurz vorstellt. Ich hab in einem Projekt nun das Membership System eingesetzt und auch seine großen Schattenseiten kennengelernt.
Der erste große Kritikpunkt:
Da entwirft man eine 3-Tier Architektur und am Ende hängt einer der wichtigsten Teile (das Usersystem) mit in der WebApp - das ist mehr als unschön.
Mein Wunsch: Das Usersystem soll mit im Backend verschwinden.
Eine grobe Skizze (wobei man den “Service” noch in andere Schichten unterteilen kann):
Die “App.Config” sollte den ConnectionString speichern und auch die Membership-Konfiguration übernehmen.
Ich sage hier bewusst “sollte”, da ich es leider nicht ganz so perfekt hinbekommen hab.
Allerdings erst mal Schritt für Schritt: Das Membership-System muss in eine DLL rein.
Grundsätzlicher Aufbau:
- “DllMembership.Lib” ist unser Service in dem wir unseren “MembershipService” haben.
- “DllMembership.Web” ist eine gewöhnliche ASP.NET Website.
- “DllMembership.Test” ist unser UnitTest-Projekt
Schritt 1: Membership-System in der DLL Konfigurieren
Als erstes müssen wir in der App.Config folgende Konfiguration erstellen:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="ASPNETDBConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename='C:\Users\rmu\Documents\Visual Studio 2008\Projects\Blogposts\DllMembership\DllMembership.Lib\DB\ASPNETDB.MDF';Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<membership>
<providers>
<remove name="AspNetSqlMembershipProvider"/>
<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ASPNETDBConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
applicationName="/"
requiresUniqueEmail="true"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="12"
minRequiredPasswordLength="1"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
passwordStrengthRegularExpression="" />
</providers>
</membership>
</system.web>
</configuration>
Die Data Source muss natürlich entsprechend des DB Speicherortes ausgewechselt werden.
Wichtiger Hinweise: Ich verwende dieselbe DB wie aus dem anderen Blogpost.
Ganz wichtig: Damit die App.Config auch angenommen wird, müssen die Properties richtig gesetzt sein:
Jetzt fügen wir noch die “System.Web” Referenz hinzu:
Schritt 2: Service schreiben
Jetzt implementieren wir unseren sehr einfachen Service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
namespace DllMembership.Lib
{
public class MembershipService
{
public IList<User> GetUsers()
{
MembershipUserCollection col = Membership.GetAllUsers();
List<User> returnList = new List<User>();
foreach (MembershipUser user in col)
{
User u = new User();
u.Name = user.UserName;
u.Email = user.Email;
returnList.Add(u);
}
return returnList;
}
public User Login(string username, string password)
{
User returnUser = new User();
if (Membership.ValidateUser(username, password))
{
returnUser.IsLoggedIn = true;
returnUser.Name = username;
returnUser.Password = password;
return returnUser;
}
else
{
returnUser.IsLoggedIn = false;
return returnUser;
}
}
public User GetUser(string username)
{
MembershipUser user = Membership.GetUser(username);
User returnUser = new User();
returnUser.Name = user.UserName;
returnUser.Email = user.Email;
return returnUser;
}
}
}
Dieser Service gibt ein “User” Objekt zurück (im Prinzip findet ein Mapping zwischen dem MembershipUser und unserem User statt) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DllMembership.Lib
{
public class User
{
public bool IsLoggedIn { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
}
Diese “User” Klasse fungiert ebenfalls als “Result” für unsere Service-Aufrufe. Klappt zum Beispiel die Login-Methode nicht, wird einfach die “IsLoggedIn” Property auf false gesetzt.
Schritt 2.5: Unit Tests
Ich habe 3 Unit-Test Methoden geschrieben, welche die grobe Funktionalität testen. Das klappt soweit.
Schritt 3: Das Web-Projekt
Damit unser Nutzer während einer Session auch eingeloggt bleibt, müssen wir noch die Form-Authentication aktivieren.
Hier müssen wir noch den Cookie “manuell” setzen. Dazu habe ich eine AppHelper mir erstellt:
namespace DllMembership.Web
{
public static class AppUtil
{
public static User GetActiveUser()
{
if(HttpContext.Current.User.Identity.IsAuthenticated == false)
{
return new User() { IsLoggedIn = false };
}
else
{
MembershipService service = new MembershipService();
User returnValue = service.GetUser(HttpContext.Current.User.Identity.Name);
returnValue.IsLoggedIn = true;
return returnValue;
}
}
public static User Login(string username, string password)
{
MembershipService service = new MembershipService();
User returnValue = service.Login(username, password);
if (returnValue.IsLoggedIn)
{
FormsAuthentication.SetAuthCookie(returnValue.Name, true);
returnValue.IsLoggedIn = true;
}
else
{
returnValue.IsLoggedIn = false;
}
return returnValue;
}
}
}
Hierbei gibt es zwei Methoden “GetActiveUser” und “Login”.
Zum “Login”:
Diese Methode übergibt die Parameter zum Service und wenn der Login erfolgreich war, wird dieser über ein Cookie über die Session hinweg authentifiziert.
Die “GetActiveUser”:
Diese Methode schaut einfach, ob der User im HttpContext authentifiziert ist, wenn nicht, gibt es keinen angemeldeten Nutzer, ansonsten wird der aktuelle Nutzer geladen.
Schritt 4: Ausgabe des Usernamen auf der Website
DllMembership.Lib.User returnUser = AppUtil.GetActiveUser();
if (returnUser.IsLoggedIn == false)
{
this.UserName.Text = "unangemeldet";
}
else
{
this.UserName.Text = returnUser.Name;
}
Dadurch können wir leicht prüfen, ob jemand angemeldet ist, oder nicht.
Das Problem dabei
Leider geht die Lösung so wie ich sie hier gepostet habe, nicht ganz, denn man muss leider in der Web.Config die Membership Konfiguration und den ConnectionString noch extra angeben.
Das “Witzige” an der Geschichte: Die Unit-Tests laufen. Sobald dies aber auf der Webseite genutzt wird, überschreiben wohl die Web.Config Einstellungen die App.Config Einstellung - ihr könnt es gerne selber ausprobieren.
Ich finde das etwas unschön, aber verschmerzbar (bzw. fällt mir nix anderes ein).
Wenn jemand eine Lösung weiß, dann her damit
Fazit
Das ist nur ein “Prototyp”, ich habe längst nicht alles fertig mir ausgedacht und würde vielleicht noch extra Properties einbauen und den Service umbasteln. Allerdings sollte dies der erste Schritt sein um zu zeigen, wie man das Membership dahin packt, wo es hingehört: In eine andere Schicht.
[ Download Source Code ]
* In den *.config muss der ConnectionString angepasst werden
** Anmeldedaten stehen in der ReadMe.txt in WebApp Ordner
ShareThis
Was hat eigentlich das "DirectX" im Hintergrund verloren?
23.06.2008 20:51:00
|
Peter Bucher
In der Hintergrundgrafik meines Blogs findet sich schon lange auch "DirectX".
Wie wahrscheinlich die meisten wissen, handelt es sich hierbei um eine Grafik-API von Microsoft.
In der Heutigen Zeit wird alles auf 3D getrimmt. Mich als grosser Fan von Echtzeit-Strategiespielen wie bspw.:
Command & Conquer Serie, KKND Serie, Warcraft Serie, Starcraft, ...
haben die ersten Ausgaben dieser 3D-Produkte nicht wirklich angesprochen.
Die zweiten Ausgaben von Echtzeit-Strategiespielen waren schon um einiges besser, jedoch finde ich 2D in Isometrischer Ansicht immer noch prikelnder.
Dort ist die Übersicht immer schön gewahrt und das Spiel hat einen eigenen Style.
Da ich vorallem auch ein riesen Fan von KKND bin und dort ein dritter Teil wohl nicht mehr kommen wird,
kam mir die Idee sowas ähnliches selber zu machen.
Vor ca. 1 1/2 Jahren habe ich angefangen an einem Spiel zu schreiben.
Primär war es als Lernobjekt gedacht, um mit der Sprache firm zu werden, sekundär um Erfahrungen in Sachen Profiling, Performance, Grafik, ...
zu sammeln.
Ich war schon ziemlich weit, fokusierte mich aber aus verschiedensten Gründen wieder 100% auf ASP.NET und verlor das Projekt aus den Augen.
Nun, viel steht schon - jedoch würde ich Heute wieder von Vorne anfangen, da ich jetzt vieles einfach viel besser machen könnte.
Auf jeden Fall konnte ich so viele Erfahrungen sammeln und werde das Projekt wohl wieder einmal aufziehen.
Das Projekt habe ich mit Managed DirectX (1.1) angefangen. In der Zwischenzeit gab es MDX 2.0, das eingestellt wurde.
Jetzt steht der Fokus bei Microsoft auf XNA, das eine komplette Plattform für die 3D und Spieleentwicklung offenlegt.
So, das Rätsel um DirectX wurde gelöst. Wenn alles klappt, wird von mir zu diesem Thema in absehbarer Zeit auch hier wieder etwas zu finden sein :)
Baseless merge - oder wie merge ich zwei unabhängige Branches
23.06.2008 16:34:57
|
Thomas Schissler
In der Versionsverwaltung des Team Foundation Servers spielt Branching eine wichtige
Rolle. Dabei kann man ausgehend von einem bestehenden Branch eine "Kopie" erzeugen,
dort Änderungen machen und diese dann in den Ursprungsbranch zurückmergen. Leider
unterstützt die UI (Sorce Control Explorer im Visual Studio) nur das mergen in den
Ursprungsbrachn aus dem heraus dieser Branch abgezweigt wurde. Merging in andere Branches
bezeichnet man als "Baseless Merges". Wie das geht beschreibt der TFS-Guide in
einem HowTo.
patterns
& practices: Team Development with Visual Studio Team Foundation Server - Home
DocProject in Version 1.11.0 erschienen
23.06.2008 16:11:17
|
Rainer Schuster
Vor zwei Wochen, in meinem Urlaub, ist DocProject in Version 1.11.0 als Release Candidate erschienen. Es bietet einige Neuerung, vor allem im Umgang mit MAML, aber den erhofften Designer besitzt DocProject noch nicht. Die Roadmap von diesem Tool sieht hingegen sehr verheisungsvoll aus. Die Final wird mit der nächsten Version 1.12.0 erwartet. DocProject wird dann als Stable und Feature-Rich mehr oder weniger abgeschlossen werden und das Hauptaugenmerk auf DocProject 2008 gelegt. Einen MAML Editor wird es in kürze als Standalone-Version in Form einer WPF-Applikation geben, um eine frühe Implementierung vorzuzeigen. Später erfolgt dann die Integration in DocProject 2008 als VSPackage - genau das was ich eigentlich suche. Der Sandcastle Help File Builder bietet hingegen schon einen recht ansehnlichen Editor, dafür aber leider ohne IntelliSense. Dennoch macht das arbeiten mit ihm mehr Sinn, und vor allem mehr Spaß. Die Lernkurve ist zu niedrig für MAML um damit sofort anzufangen, selbst mit IntelliSense, dass aber erst etwas umständlich aktiviert werden muss. Der Editor vom SHFB kann sofort ohne große Kenntnisse eingesetzt werden. Es ist relativ selbsterklärend und zudem in sehr kleinem Umfang sehr gut dokumentiert (wie ich es vom SHFB gewohnt bin). Zu diesem Thema aber später mehr in einem dotnet-forum Artikel aus meiner Serie "Vom Code zur Dokumentation" von dem ich vor einiger Zeit schon den ersten Artikel mit einer kurzen Einführung geschrieben habe.
Download details: Team Foundation Installation Guide
23.06.2008 13:13:22
|
Thomas Schissler
Ein Dokument auf das ich immer verweise, wenn es um die Installation des Team Foundation
Servers geht ist der TFS2008 Installation Guide. Deshalb hier mal der Link für alle,
die einen TFS aufsetzen wollen. Leider funktioniert das mit CD rein und Setup aufrufen
nicht. Aber wenn man die Installationsanweisung befolgt, geht's meisten problemlos.
Ansonsten einfach mich anmailen, ich versuche dann gerne weiterzuhelfen.
Download
details: Team Foundation Installation Guide
Sandcastle nicht mehr auf Codeplex
23.06.2008 10:12:43
|
Rainer Schuster
Zurück aus meinem Urlaub musste ich feststellen, dass sich so einiges in der IT-Welt geändert hat. Unter anderem musste ich feststellen, dass Sandcastle nicht mehr auf Codeplex gehostet wird. Der neue temporäre Download findet sich auf den MSDN-Seiten von Microsoft. Wer also mit meinen bisherigen Links und Anleitungen Probleme hat, unter dem genannten Link ist die aktuellen Version erreichbar. Zur Zeit wir darüber sinniert, was mit Sandcastle passieren soll. Folgende Optionen stehen zur Debatte:
- Auf code.msdn.microsoft.com hosten
- einen relaunch auf codeplex als Opensource Projekt mit Sourcecode
Was ist Community?
23.06.2008 08:20:57
|
Norbert Eder
Eine Community ist eigentlich nicht nur ein Blog bei dem sich einige Personen angemeldet haben. Eine Community ist nicht nur ein Forum mit zahlreichen Usern, die sich über unterschiedlichste Themen unterhalten. Eine Community ist wesentlich mehr.
Eine Community zeichnet sich dadurch aus, dass
- sich Menschen gegenseitig bei Problemen helfen
- gemeinsam Ideen umgesetzt werden
- gemeinsam Wissen verteilt und somit die gemeinsame Community gestärkt wird
- die einzelnen Community-Betreiber zusammen halten um gemeinsam stark zu werden
- einzelne Community-Betreiber sich an Abgemachtes halten um wirklich gemeinsam für die Community da sein zu können
- jeder die Möglichkeit besitzt seine Stärken auszuspielen
Und natürlich könnte man noch weitere Punkte hinzufügen. Schade ist nur, dass sich einige absolut nicht daran halten und lieber ihren ganz persönlichen Weg beschreiten. Dagegen ist auch nichts einzusetzen.
Traurig finde ich jedoch, dass es immer jemanden geben muss, der gegen
gemeinsam definierte Spielregeln verstößt und das auch noch für gut befindet. Für mich ist Derartiges nicht mit dem Community-Gedanken zu vereinbaren.
Anscheinend sind Regeln da, um gebrochen zu werden. Gestern Beschlossenes gilt heute nicht mehr ohne auch nur einen Laut von sich zu geben. Und das dort, wo eigentlich am gleichen Strang gezogen werden sollte.
Das hat keinen Wert. Weder auf persönlicher Ebene, noch in Bezug auf die Community. Wenn es unbedingt so sein muss, make it so, aber
ohne mich.
Source Analysis For C# Checkin Policy
22.06.2008 21:22:26
|
Thomas Schissler
WPF: Offene Fenster im Überblick behalten
22.06.2008 20:02:12
|
Norbert Eder
Wir kennen es wohl alle: Das "Window"-Menü mit allen offenen Fenstern derselben Applikation. Vor allem in den Office-Produkten war dies immer wieder zu finden. Doch wie kann dies unter WPF implementiert werden? Dieser Artikel zeigt wie's geht. Und so kann das Endresultat aussehen (es ist zwar nicht hübsch, aber es funktioniert):
Zu Beginn stellt sich natürlich dir Frage ob es da nicht schon etwas Fertiges gibt. Ja. Gibt es. Unter
Application.Current.Windows findet sich die aktuelle Auflistung aller geöffneten Fenster. Einziger Nachteil: Diese stecken in einer eigenen
WindowCollection, welche lediglich
ICollection und
IEnumerable implementiert. Damit jedoch Data Binding möglich ist, wäre eine
ObservableCollection notwendig.
Damit es uns Entwicklern nicht fad wird, müssen wir daher selbst in die Tasten klopfen und unser eigenes System entwickeln, wollen wir doch Data Binding verwenden!
Zuerst benötigen wir eine simple Datenklasse, welche Informationen für uns hält und auch später wieder zugänglich macht:
public class WindowInformation
{
private Window _window;
public WindowInformation(Window window)
{
_window = window;
}
public Window Window
{
get { return _window; }
}
public int WindowHashCode
{
get { return _window.GetHashCode(); }
}
public String Title
{
get { return _window.Title; }
}
public ImageSource Icon
{
get { return _window.Icon; }
}
}
Die Datenklasse fungiert in diesem Fall lediglich als Wrapper-Klasse, könnte aber ohne großen Aufwand um weitere Informationen angereichert werden.
Damit nun Data Binding verwendet werden kann, benötigen wir eine - wie schon angesprochen - ObserableCollection:
public class WindowInformationCollection :
ObservableCollection<WindowInformation>
{
}
Nun wird eine
Manager-Klasse benötigt, welche die Liste der geöffneten Fenster hält und zusätzliche Funktionen wie Entfernen eines Fensters oder das Zurückgeben eines speziellen Fensters zur Verfügung stellt. Dieser Manager wurde mit dem Singleton-Pattern umgesetzt, damit sichergestellt ist, dass nur eine Instanz davon pro gestarteter Anwendungsinstanz vorhanden ist.
public class WindowManager
{
private static WindowManager _manager;
private WindowInformationCollection _openWindows =
new WindowInformationCollection();
private WindowManager() { }
public static WindowManager GetInstance
{
get
{
if (_manager == null)
_manager = new WindowManager();
return _manager;
}
}
public WindowInformationCollection OpenWindows
{
get { return _openWindows; }
}
public Window GetOpenWindow(int hashCode)
{
foreach (WindowInformation wi in _openWindows)
{
if (wi.WindowHashCode == hashCode)
{
return wi.Window;
}
}
return null;
}
public bool RemoveOpenWindow(int hashCode)
{
WindowInformation windowToRemove = null;
foreach (WindowInformation wi in _openWindows)
{
if (wi.WindowHashCode == hashCode)
{
windowToRemove = wi;
break;
}
}
if (windowToRemove != null)
{
_openWindows.Remove(windowToRemove);
return true;
}
return false;
}
}
Zu guter Letzt wird noch ein Handler implementiert, der schlussendlich in das
Window-Element des XAMLs eingebunden werden kann und somit ein Fenster in das System einbindet:
public class WindowInformationHandler
{
public static readonly DependencyProperty
IsHandledProperty =
DependencyProperty.RegisterAttached("IsHandled",
typeof(bool), typeof(WindowInformationHandler),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnIsHandledChanged)));
private static void OnIsHandledChanged(
DependencyObject dObj,
DependencyPropertyChangedEventArgs e)
{
Window openWindow = dObj as Window;
if (openWindow != null)
{
openWindow.Loaded +=
new RoutedEventHandler(WindowLoaded);
openWindow.Closed +=
new EventHandler(WindowClosed);
}
}
public static bool GetIsManaged(DependencyObject dObj)
{
return (bool)dObj.GetValue(IsHandledProperty);
}
public static void SetIsManaged(
DependencyObject dObj,
bool value)
{
dObj.SetValue(IsHandledProperty, value);
}
private static void WindowClosed(
object sender, EventArgs e)
{
Window closedWindow = sender as Window;
if (closedWindow != null)
{
WindowManager.GetInstance.RemoveOpenWindow(
closedWindow.GetHashCode()
);
openWindow.Loaded -=
new RoutedEventHandler(WindowLoaded);
openWindow.Closed -=
new EventHandler(WindowClosed);
}
}
private static void WindowLoaded(
object sender, RoutedEventArgs e)
{
Window openWindow = sender as Window;
if (openWindow != null)
{
WindowInformation winInfo =
new WindowInformation(openWindow);
WindowManager.GetInstance.OpenWindows.Add(winInfo);
}
}
}
Wird die Eigenschaft
IsHandled auf
true gesetzt, werden zwei Events (Loaded und Closed) registriert. Auf diese wird in weiterer Folge reagiert, um das Fenster nach erfolgtem Laden in die Liste der geöffneten Fenster aufzunehmen bzw. davon auch wieder zu entfernen.
In XAML wird dies folgendermaßen in das Window-Element eingebunden:
local:WindowInformationHandler.IsManaged="true"
Damit ist dieses System fertig und kann angewandt werden.
Das XAML-Markup für oben gezeigten Screenshot sieht so aus:
Und hier noch der Inhalt aus dem Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
mnuWindows.ItemsSource =
WindowManager.GetInstance.OpenWindows;
}
private void NewWindow(object sender,
RoutedEventArgs e)
{
MainWindow window = new MainWindow();
window.Title = String.Format("Open Window {0}",
Application.Current.Windows.Count);
window.Show();
}
private void ShowWindow(object sender,
RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
WindowInformation wi = mi.DataContext
as WindowInformation;
if (wi != null)
{
wi.Window.Focus();
}
}
}
}
Voilá!
Einen SqlSiteMapProvider ohne direkte Datenbankanbindung nutzen.
22.06.2008 17:35:06
|
Klaus Bock
Als ich vor ca. 2 Jahren begann mich mit einem SiteMapProvider zu befassen der als SiteMapDataSource eine SQL-Datenbank benutzt, bin ich auf diesen Artikel von Jeff Prosise gestoßen. In seiner Implementierung hatte er schon fast alle meine Anforderungen erfüllt. Er benutzt die SqlCacheDependency zum überwachen von Änderungen an der Sitemap Tabelle in der Datenbank, sowie das securityTrimmingEnabled-Konfigurationsattribut welches den Wert der Eigenschaft SecurityTrimmingEnabled des SiteMapProvider setzt und somit die Verwendung von Roles unterstützt. Was mit allerdings fehlte, war eine "Entkoppelung" des SiteMapProvider von der Datenbank. Da in den meisten ASP.NET-Anwendungen exzessiver Gebrauch von der Datenbankverbindung gemacht wird wollte ich den SqlSiteMapProvider so gestalten, dass er nicht bei jedem laden der Seite eine Verbindung zur Datenbank aufbaut. Es sollte auch eine Möglichkeit geschaffen werden den Provider über einen Webdienst mit der Datenbank kommunizieren zu lassen. Dabei sollte auch gleich die Authentifizierung mit Hilfe der, in dieser Artikelreihe beschriebenen, SoapAuthHeader-Klasse ermöglicht werden. Das Ganze sollte auch noch einfach in der web.config konfiguriert werden.
Der zuletzt angesprochene Punkt: Konfiguration in der web.config ließ sich am leichtesten umsetzen. Da die Klasse SqlSiteMapProvider von der abstrakten Klasse StaticSiteMapProvider erbt, wird die Methode Initialize überschrieben. Diese Methode wird vom Framework bei der Initialisierung des Provider aufgerufen und die gesamte, den Provider betreffende, Konfiguration in der web.config als NameValueCollection an die Initialize-Methode übergeben. Jetzt braucht man nur noch die einzelnen Konfigurationsattribute auf ihren Wert zu prüfen und auszuwerten. Um zu unterscheiden ob eine direkte Datenbankverbindung genutzt wird, habe ich das Konfigurationsattribut directConnection hinzugefügt. Dieses Attribut wird in der überschriebenen Initialize-Methode in einen boolschen Wert gecastet und ausgewertet. Der Konfigurationsbereich in der web.config könnte so aussehen:
<configuration>
<siteMap defaultProvider="SqlSiteMapProvider" enabled="true">
<providers>
<clear/>
<add name="SqlSiteMapProvider" type="TestSpace.Web.SqlSiteMapProvider"
securityTrimmingEnabled="true" secureQueryStringEnabled="true"
directConnection="false" cacheKey="sitemapDataSet"/>
</providers>
</siteMap>
</configuration>
In der Initialize-Methode wird geprüft ob das Attribut in der web.config angegeben ist und dann in eine Variable vom Typ bool gecastet.
// prüfen ob directConnection in der web.config angegeben ist
if (string.IsNullOrEmpty(config["directConnection"]))
{
config.Remove("directConnection");
config.Add("directConnection", "true");
}
bool.TryParse(config["directConnection"], out isDirectConnection);
config.Remove("directConnection");
Die Variable isDirectConnection wird nun an mehreren Stellen in einem if-Statement verwendet um auf die vorliegende Konfiguration zu reagieren. Falls isDirctConnection true zurückgibt, wird, wie im Original Code, ein SqlDataReader verwendet um die Sitemap-Struktur zu erstellen. Wird false zurückgegeben, liegt im HttpRuntime.Cache ein DataSet vor. In diesem Fall wird ein DataTableReader verwendet um die Sitemap-Struktur zu erstellen. Beide Szenerien lassen sich ohne größeren Aufwand nutzen, da das Argument reader der beiden Methoden CreateSiteMapNodeFromDataReader(reader) und GetParentNodeFromDataReader(reader) vom Typ DbDataReader ist und somit sowohl einen SqlDataReader als auch einen DataTableReader akzeptiert. Insofern sind die Änderungen an der SqlSiteMapProvider-Klasse abgeschlossen.
Um das benötigte DataSet im HttpRuntime.Cache zu verwalten kann natürlich in jedem Anwendungsfall des SqlSiteMapProvider ein eigenes Datahandling geschrieben werden. Doch jedes einzelne Mal mich selbst um die Daten im Cache zu kümmern erschien mir zu mühsam. Also habe ich nach einem Weg gesucht um die benötigten Daten nur einmal, beim Start der Anwendung, zur Verfügung zu stellen. Es war klar, dass hier nur die Methode Application_Start der Global-Klasse in Betracht kam. Jetzt musste noch eine Klasse her, welche sich einfach in der Global-Klasse initialisieren lies und sich um die Cache-Verwaltung kümmerte. Um die Zugehörigkeit zum SqlSiteMapProvider zu zeigen, habe ich diese Klasse SqlSiteMapCacheHandler genannt. Da ich mir zur Aufgabe gemacht hatte die Daten von einem Webdienst liefern zu lassen, musste auch die Handhabung eines Webdienst-Proxy sowie die zugehörige Authentifizierung möglichst abstrakt gehalten werden. Des weiteren soll ebenfalls auf Änderungen in der zugrundeliegenden Datenbanktabelle reagiert werden. Hier habe ich mich für die Verwendung einer CacheDependency mit einem Cacheschlüssel entschieden. Dieses erschien mir am einfachsten, da Änderungen an der Sitemap-Tabelle sicherlich aus der Web-Anwendung heraus getätigt werden und somit der Cacheschlüssel einfach, im Zuge der Änderung, geändert werden kann.
Etwas komplexer verhält es sich mit der Verwendung eines Webdienst-Proxy und der Authentifizierung. Es müssen verschiedenen Objekte an die SqlCacheHandler-Klasse übergeben werden. Im einzelnen sind dies:
- Der eigentliche Webdienst-Proxy als Object.
- Die Webdienst-Proxy Methode, welche die benötigten Daten anfordert.
- Der für die Authentifizierung zuständige SoapHeader als Object.
- Die Gültigkeitsdauer des SoapHeader.
Also wurden in der SqlCacheHandler-Klasse die benötigten Eigenschaften des jeweiligen Typs angelegt.
#region Properties
/// <summary>
/// Der Name des Schlüssels unter dem das DataSet im Cache abgelegt werden soll.
/// Es muss der gleiche Name verwendet werden wie in der Konfiguration
/// des <see cref="T:TestSpace.Web.SqlSiteMapProvider"/>.
/// </summary>
/// <value>Setzt den Wert des privaten Feldes cacheKey oder gibt ihn zurück.</value>
/// <remarks>n/a</remarks>
public string CacheKey
{
get { return this.cacheKey; }
set { this.cacheKey = value; }
}
/// <summary>
/// Der Referenzschlüssel der überwacht werden soll. Initialisierungswert ist <c>false</c>.
/// Das bedeutet, Daten sind nicht geändert.
/// </summary>
/// <value>Setzt den Wert des privaten Feldes referenceKey oder gibt ihn zurück.</value>
/// <remarks>
/// Ein zusätzlicher Schlüssel, der für das verwendete <see cref="T:System.Web.Caching.CacheDependency"/>
/// -Objekt benötigt wird. Der Wert dieses Schlüssels, <c>true</c> oder <c>false</c>, sollte bei
/// Änderungen an der Datenbanktabelle ebenfalls auf <c>true</c>, als Daten geändert, gesetzt werden.
/// </remarks>
public string ReferenceKey
{
get { return this.referenceKey; }
set { this.referenceKey = value; }
}
/// <summary>
/// Die WebServiceProxy-Klasse, die das DataSet liefert.
/// </summary>
/// <value>Setzt den Wert des privaten Feldes proxy oder gibt ihn zurück.</value>
/// <remarks>
/// Falls der übergebene WebServiceProxy <see cref="T:System.Web.Services.Protocols.SoapHeader"/>
/// oder andere Methoden zur Authentifitierung verwendet, muss dieser an die Eigenschaft
/// <see cref="P:TestSpace.Web.SqlSiteMapCacheHandler.ProxyAuhHeader"/> übergeben werden.
/// </remarks>
public object Proxy
{
get { return this.proxy; }
set { this.proxy = value; }
}
/// <summary>
/// Die <see cref="T:System.Web.Services.Protocols.SoapHeader"/>-Klasse,
/// die zur Authentifizierung verwendet wird.
/// </summary>
/// <value>Setzt den Wert des privaten Felds proxyAuthHeader oder gibt ihn zurück.</value>
/// <remarks>n/a</remarks>
public object ProxyAuhHeader
{
get { return this.proxyAuthHeader; }
set { this.proxyAuthHeader = value; }
}
/// <summary>
/// Die Gültigkeit der AuthHeader Klasse in Sekunden.
/// </summary>
/// <value>Setzt den Wert des privaten Feldes proxyAuthHeaderExpires oder gibt ihn zurück.</value>
/// <remarks>Der Standardwert ist auf 10 Sekunden festgelegt.</remarks>
public int ProxyAuthHeaderExpires
{
get { return this.proxyAuthHeaderExpires; }
set { this.proxyAuthHeaderExpires = value; }
}
/// <summary>
/// Der Name der Methode im <see cref="P:TestSpace.Web.SqlSiteMapCacheHandler.Proxy"/>,
/// die das DataSet für den <see cref="T:TestSpace.Web.SqlSiteMapProvider"/> liefert.
/// </summary>
/// <value>Setzt den Wert des privaten Feldes getDataMethod oder gibt ihn zurück.</value>
/// <remarks>Die aufzurufende Methode darf keine Parameter benötigen.</remarks>
public string GetDataMethod
{
get { return this.getDataMethod; }
set { getDataMethod = value; }
}
#endregion
Als einzige öffentliche Methode ist die Methode Initialize vorhanden die, nach der Zuweisung der Eigenschaften, einmal aufgerufen wird. In der Global-Klasse sieht das dann in etwa so aus:
public class Global : HttpApplication
{
// Neue Instanz des WebService-Proxy
private GetSiteMapProxy siteMapProxy = new GetSiteMapProxy();
// Neue Instanz vom SoapAuthHeader des WebService-Proxy
private SoapAuthHeader authHeader = new SoapAuthHeader();
// neue Instanz vom SqlSiteMapCacheHandler
private SqlSiteMapCacheHandler handler = new SqlSiteMapCacheHandler();
/// <summary>
/// Standard-Konstruktor
/// </summary>
public Global()
{
//Auskommentierung der folgenden Zeile bei Verwendung von Designkomponenten aufheben
//InitializeComponent();
}
/// <summary>
/// Wird beim Start der Anwendung ausgeführt.
/// </summary>
void Application_Start(object sender, EventArgs e)
{
// SqlSiteMapCacheHandler initialisieren
handler.CacheKey = "sitemapDataSet";
handler.ReferenceKey = "sitemapKey";
handler.Proxy = siteMapProxy;
handler.GetDataMethod = "getData";
handler.ProxyAuhHeader = authHeader;
handler.ProxyAuthHeaderExpires = 30;
handler.Initialize();
}
// hier weitere Methoden
}
Wenn die Methode Initialize aufgerufen wird, prüft sich zunächst ob die privaten Felder proxy und getDataMethod mit Werten belegt sind. Anschließend wird überprüft ob die beiden Cacheschlüssel schon im Cache vorhanden sind.
public void Initialize()
{
// prüfen ob die Felder proxy und getDataMethod mit Werten belegt sind.
if (this.proxy == null || this.getDataMethod == null)
{
throw new EmptyPropertyException(Resources.EmptyProxyAndGetData);
}
// prüfen ob die beiden CacheSchlüssel schon im Cache vorhanden sind.
if (HttpRuntime.Cache[this.referenceKey] == null
&& HttpRuntime.Cache[this.cacheKey] == null)
{
HttpRuntime.Cache.Insert(this.referenceKey, false);
this.CacheSiteMap();
}
// Schlüssel sind vorhanden, aber Daten wurden geändert.
else
{
if ((bool)HttpRuntime.Cache[this.referenceKey])
{
HttpRuntime.Cache[this.referenceKey] = false;
this.CacheSiteMap();
}
}
}
Sind beide Schlüssel noch nicht vorhanden werden sie ins Cache eingefügt und anschließend die private Methode CacheSiteMap ausgeführt. Sollten die Schlüssel bereits vorhanden sein, wird überprüft ob die Daten im Cache noch gültig sind. Die erwähnte private Methode CacheSiteMap kümmert sich um das eigentliche Speichern des DataSet im Cache, sowie um das erzeugen der CacheDependency.
private void CacheSiteMap()
{
// den ReferenceSchlüssel in das cacheKeys-Array schreiben.
// wird zur Überwachung der Gültigkeit des Cache-Objekt benötigt.
this.cacheKeys[0] = this.referenceKey;
// Eine Cacheabhängikeit zum referenceKey erzeugen.
CacheDependency dependency = new CacheDependency(null, this.cacheKeys);
// Das DataSet in das Cache schreiben.
HttpRuntime.Cache.Insert(
this.cacheKey,
this.GetDataSet(),
dependency,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.High,
this.SitemapRemovedCallback);
}
Als zweites Argument erwartet die Cache.Insert-Methode ein Objekt, welches im Cache gespeichert werden soll. Anstatt eines vorliegenden DataSet, wird hier die private Methode GetDataSet aufgerufen, welche das benötigte DataSet liefert. Da die Methode einen beliebigen Webdienst-Proxy, aus der Eigenschaft Proxy, verarbeiten muss, als auch der Methodenname welcher die benötigten Daten liefert auch jedesmal ein anderer sein kann, wird hier ein bisschen Reflection benötigt. Auf diese Art und Weiße kann auch gleich der SoapHeader des Webdienst-Proxy dynamisch erzeugt und zugewiesen werden. Für das Lesen und Zuweisen von Eigenschaften in Klassen die erst zur Laufzeit bekannt sind, bietet das Framework die Klasse PropertyInfo an. Also braucht nur von jeder Eigenschaft der SoapAuthHeader-Klasse ein PropertyInfo-Objekt erzeugt zu werden um die Werte der jeweiligen Eigenschaft zu bearbeiten.
byte[] hash = Fingerprint.CreateHash(
new object[] { DateTime.Now, this.proxyAuthHeaderExpires, false });
// mittels Reflection die Properties der SoapAuthHeader Klasse holen.
PropertyInfo proxyAuthHeaderValue = this.proxy.GetType().GetProperty("SoapAuthHeaderValue");
PropertyInfo authHeaderCreated = this.proxyAuthHeader.GetType().GetProperty("Created");
PropertyInfo authHeaderExpires = this.proxyAuthHeader.GetType().GetProperty("Expires");
PropertyInfo authHeaderIsEditMode = this.proxyAuthHeader.GetType().GetProperty("IsEditMode");
PropertyInfo authHeaderHashValue = this.proxyAuthHeader.GetType().GetProperty("HashValue");
// Die Werte in den Properties der SoapAuthHeader Klasse setzen
if (authHeaderCreated != null)
{
authHeaderCreated.SetValue(this.proxyAuthHeader, DateTime.Now, null);
}
if (authHeaderExpires != null)
{
authHeaderExpires.SetValue(this.proxyAuthHeader, this.proxyAuthHeaderExpires, null);
}
if (authHeaderIsEditMode != null)
{
authHeaderIsEditMode.SetValue(this.proxyAuthHeader, false, null);
}
if (authHeaderHashValue != null)
{
authHeaderHashValue.SetValue(this.proxyAuthHeader, hash, null);
}
// Die SoapAuthHeader-Klasse an das Property SoapAuthHeaderValue der
// WebService-Proxy Klasse übergeben
if (proxyAuthHeaderValue != null)
{
proxyAuthHeaderValue.SetValue(this.proxy, this.proxyAuthHeader, null);
}
Ähnlich verhält es sich mit dem Methodenname der jeweiligen Webdienst-Proxy-Klasse. Hierfür wird allerdings die MethodInfo-Klasse verwendet. Zuerst wird ein MethodInfo-Objekt mit dem Methodennamen aus dem Feld getDataMethod erzeugt. Anschließend wird geprüft ob das MethodInfo-Objekt null ist und ob der Rückgabe-Typ der Methode ein DataSet ist. Sollten beide Bedingungen erfüllt sein, wird mittels MethodBase.Invoke die Methode im Webdienst-Proxy aufgerufen.
// mittels Reflection die Methode holen welche das DataSet liefert.
MethodInfo proxyGetData = this.proxy.GetType().GetMethod(this.getDataMethod);
// Falls die Methode gefunden wurde und der RückgabeTyp ein DataSet ist
// wird die Methode mit Invoke aufgerufen.
if (proxyGetData != null && proxyGetData.ReturnType == typeof(DataSet))
{
return (DataSet)proxyGetData.Invoke(this.proxy, new object[] { });
}
Nun muss nur noch das zurückgegebene Objekt in ein DataSet gecastet und als solches zurückgegeben werden. Die oben beschriebene Methode CacheSiteMap fügt dieses jetzt in den Cache ein und kann somit vom SqlSiteMapProvider verwendet werden.
Da die hier beschriebenen Klassen Bestandteil eines größeren Projektes sind, habe ich hier kein Projekt zum Download angeboten. Sollte Interesse bestehen, kann ich die Klassen aus dem Gesamtprojekt herauslösen und zum herunterladen bereitstellen. Einfach kurz einen Kommentar schreiben.
Zuerst mit Firefox entwickeln, danach mit Internet Explorer
21.06.2008 11:09:00
|
Peter Bucher
Ihr werdet mich wohl alle schlagen... ich verwende lieber den Internet Explorer zum Surfen als den Firefox.
Ggf. kann das wieder umkehren, je nach dem wie sich der Firefox entwickelt.
Früher habe ich beim Entwickeln von einem (X)Html / CSS Prototyp immer zuerst im Internet Explorer getestet
und später im Firefox.
Ich musste aber einsehen, das dies ein schlechtes Vorgehen ist.
Fakt ist dass sich der Firefox bzw. alle Mozilla Browser viel besser an den Standard halten, was (X)Html und CSS angeht.
Durch diese Tatsache gibt es weniger Arbeit und der Prototyp kommt viel näher an den Standard.
Wenn schlussendlich alles sauber läuft wird noch mit dem IE und ggf. anderen Browsern getestet.
Die folgenden Anpassungen sind weitaus weniger, als wenn zuerst für den IE entwickelt wird (Auch wenn der Code validiert wird).
Zudem ist es natürlich wichtig, einen Doctype festzulegen und den Code validieren zu lassen.
Es muss nicht immer 100% valid sein - aber die gröbsten Fehler sollten sicher ausgemerzt werden, um gröbere Fehlverhalten auszuschliessen.
Get the names of databases on a SQL Server
20.06.2008 18:34:24
|
Andre Loker
For administrative tasks you might need the names of all databases on a given SQL Server. Luckily SQL Server comes with some neat stored procedures that help a lot, for example:
EXEC sp_databases; -- get name, size and remarks
EXEC sp_helpdb; -- get name, size, owner, dbid, creation date,
-- status and compatibility level
Those two SPs are certainly nice to have, but they return more than you might need. Given that it is not so easy to perform a SELECT on the results here's a simple query to return the names of all (online) databases:
SELECT db_name(database_id)
FROM sys.master_files
WHERE state = 0 -- only fetch databases that are online
GROUP BY database_id;
Admittedly I did not come up with this all by myself. I simply looked at what sp_databases does and extracted the stuff I needed :-)
Using table valued results of stored procedures
20.06.2008 18:31:30
|
Andre Loker
If a stored procedure returns a table of data, it's not as easy as one might think to work with the result. Assume the following scenario:
- we have a table Account
- we have a (admittedly silly) stored procedure that performs some query and returns "Account" rows:
CREATE PROCEDURE sp_GetAccounts
AS
SELECT * FROM Account;
- we want to perform additional filtering & projection on the data returned by the SP, like:
SELECT UserName, Email
FROM (EXEC sp_GetAccounts)
WHERE Email LIKE '%.de'
ORDER BY UserName ASC;
This, however, does not work:
Incorrect syntax near the keyword 'EXEC'.
It seems that we cannot use the result of the SP as a normal table. But here's a little trick that will do what we want:
-- create a table variable (ie. a temporary in-memory table)
DECLARE @results TABLE (
ID int,
UserName nvarchar(50),
Email nvarchar(256),
HashedPasswod nvarchar(32),
Salt nvarchar(16)
);
-- fill it with the results from the SP
INSERT INTO @results EXEC sp_GetAccounts;
-- perform normal queries on the table
SELECT UserName, Email
FROM @results
WHERE Email LIKE '%.de'
ORDER BY UserName ASC;
We simply create a table variable compatible to the Account table to temporarily hold the results of the stored procedure. This table is filled using the SP (INSERTs work with SPs). We can then execute queries against that table variable as we like. By using a table variable (instead of a temporary table) everything is held in memory and we don't need to drop the table explicitly after we're done using it.
I'm not a SP guru, so if there are simpler ways to achieve the same result, drop me a comment.
Aero überall - Transparenter Browser
20.06.2008 15:57:00
|
Jens Peter Kleinau
Unter Vista SP1 kann es ab und zu selbst für erfahrene Programmierer noch interessante Überraschungen geben.
Vista erlaubt, die Aero Fläche des Fensters über den normalen Rahmen hinweg zu verwenden und somit in die Inhaltsfläche des Fensters zu übernehmen. Dazu muss man einfach die notwendige API Funktion "DwmExtendFrameIntoClientArea" verwenden (die betreffenden Funktionen...
[[ This is a content summary only. Visit my website for full links, other content, and more! ]]
CustomControl im App_Code Ordner registrieren
20.06.2008 12:21:00
|
Peter Bucher
In einem WebSite-Project (Siehe: VS2008 ASP.NET Web Application Project und Kommentare dazu) gibt es den App_Code Ordner.
Wenn dort ein Control als Codedatei (*.vb / *.cs) angelegt wird, kann dieses nicht wie bei einem externen Projekt oder einem wie bei einem WAP-Projekt referenziert werden.
Normalerweise sieht das Referenzieren so aus:
ASPX:
<%@ Register TagPrefix="pb" Assembly="MeinAssembly" Namespace="MeinControl" %>
Bei einem WAP-Projekt ist "MeinAssembly" der Assemblyname, bei einer externen Bibilothek (DLL) genau so.
Ein Website-Projekt hat aber kein benanntes Assembly, sondern mehrere autogenerierte Assemblies für die komplette Site.
Damit dort auch referenziert werden kann, muss lediglich das Assembly-Attribut weggelassen werden:
ASPX:
<%@ Register TagPrefix="pb" Namespace="MeinControl" %>
Gleiche Vorgehensweise klappt übrigens auch beim Registrieren über die web.config, siehe:
Testing und WPF (MVC, Unit Tests und andere hilfreiche Dinge)
20.06.2008 10:52:00
|
Jens Peter Kleinau
WPF Oberflächen sind im Kommen und das ist auch gut so. Die meisten der aktuell entstehenden Anwendungen sind eher klein und handlich, wenn nicht sogar bezüglich Silverlight eher winzig zu nennen. Doch es gibt auch Ausnahmen und diese Großproduktionen für die so genannten wirtschaftlichen Keyplayer unterliegen völlig anderen Prozessbedingungen (in mehrerer Wortbedeutung) als eine kleine...
[[ This is a content summary only. Visit my website for full links, other content, and more! ]]
Firefox 2.0 und 3.0 parallel betreiben
20.06.2008 10:43:00
|
Peter Bucher
Für alle Webentwickler ein Muss, die Lösung heisst "Firefox portable", da diese nicht auf Profile zurückgreift.
Download unter:
Um beide Versionen parallel laufen zu lassen, gibt es einen Tweak, zu finden unter:
Update (Bessere Lösung mit der normalen Firefox Version):
Via Firefox 2 und Firefox 3 parallel betreiben
Firefox 2 und 3 - Scrollbalken immer da, neue Lösung
20.06.2008 10:31:00
|
Peter Bucher
Wie bspw. in Jürgens Posting "CSS: 100% Höhe bei DIVs" erwähnt, gibt es beim YAML-Erfinder eine Lösung damit der Scrollbalken unter Firefox immer erscheint.
Der Trick ist, dem html jeweils auf 100.01% Höhe zu setzen, in etwa so:
CSS:
html { height:100.01%; }
Heute musste ich feststellen, dass diese Lösung mit Firefox 3.0 nicht mehr zieht.
Auf der YAML Webseite fand ich dann eine Lösung, die schlussendlich im Firefox 2.0 sowie auch 3.0 sein Werk tut:
CSS:
html { height: 100%; margin-bottom: 1px; }
Ich muss sagen, das ich enttäuscht bin:
1. Sollte der Scrollbalken immer angezeigt werden, genau wie im IE - alles andere ist IMO Quatsch
2. War das Problem bekannt
3. Wäre eine neue Version dazu da, Probleme zu beheben und nicht noch neue Workarounds hervorzubringen
In diesem Sinne: Firefox Entwickler, bitte macht doch dies dem IE mal nach.
Old School Point & Click Adventure in Silverlight im Stil klassischer SCUMM-Adventures wie Maniac Mansion oder Zak McKracken
20.06.2008 10:20:00
|
Steffen Ritter
Wer sagt dass Silverlight-RIAs immer ernsthafte Businessanwendungen oder HD-Videoplayer sein müssen: Buddy Knavery ist ein Point & Click Adventure im Stil der klassischen SCUMM-Adventures wie Maniac Mansion. In dem kostenlosen Adventure übernimmt der Spieler die Rolle des Undercover Cops Buddy Knavery um eine Welle brutaler Verbrechen in Lazarus Falls, Oregon aufzuklären. Direkt zum Spiel Buddy Knavery [Link].
Ach, bei so viel gut gemachtem Retro-Spaß werde ich tatsächlich ein wenig sentimental, erinnert mich das doch an meine Magisterarbeit zu Adventure, Zork, Monkey Island und Silent Hill, damals vor vielen Jahren.
HowTo: PicLens und andere MediaRSS Clients für die eigene Webseite nutzen (MediaRSS mit LINQ to XML erstellen)
19.06.2008 23:52:38
|
Robert Mühsig
Dieses HowTo ist im Zusammenhang mit dem normalen “RSS XLINQ” Post entstanden - ist allerdings wesentlich cooler.
Worum geht es?
Es geht um den “MediaRSS” Standard und wie man diesen für sich nutzen kann. Noch nie davon gehört? Ich bis heute auch nicht.
Allerdings gibt es ein bekanntes Firefox Plugin welches mit darauf basiert - die Rede ist von “PicLens“.
Was kann “PicLens”?
“PicLens” bietet eine sehr schicke Oberfläche für verschiedene bekannte Dienste wie YouTube, Google Bildersuche, Flickr oder auch Amazon:
Hier mal die Amazon-Ansicht:
Media RSS
PicLens kann auch mit dem oben genannten “MediaRSS” Standard umgehen - auf der Seite ist auch gut beschrieben wie man das macht. Da wir bereits ein RSS Feed mit XLinq erstellt haben, dürfte das ja nicht sonderlich schwerer sein.
XLINQ
Wir haben den selben Projektaufbau - nur in der ASHX müssen wir die Erstellung etwas anpassen:
XNamespace media = "http://search.yahoo.com/mrss";
XNamespace atom = "http://www.w3.org/2005/Atom";
public void ProcessRequest(HttpContext context)
{
XDocument document = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("rss",
new XAttribute("version", "2.0"),
new XAttribute(XNamespace.Xmlns + "media", media),
new XAttribute(XNamespace.Xmlns + "atom", atom),
new XElement("channel", this.CreateElements())
));
context.Response.ContentType = "text/xml";
document.Save(context.Response.Output);
context.Response.End();
}
private IEnumerable<XElement> CreateElements()
{
List<XElement> list = new List<XElement>();
for(int i = 1; i < 100; i++)
{
XElement itemElement = new XElement("item",
new XElement("title", i),
new XElement("link", "Code-Inside.de"),
new XElement(media + "thumbnail",
new XAttribute("url", "http://code-inside.de/blog/wp-content/uploads/image-thumb" + i + ".png")),
new XElement(media + "content",
new XAttribute("url", "http://code-inside.de/blog/wp-content/uploads/image-thumb" + i + ".png"))
);
list.Add(itemElement);
}
return list;
}
In dem ASHX Handler haben wir nun noch zwei zusätzliche XNamespaces deklariert. Diese sind (laut der Piclens Seite) notwendig um erstmal dieses XML zu erzeugen:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:atom="http://www.w3.org/2005/Atom">
...
</rss>
Diese Namespaces werden über ein XAttribute hinzugefügt. Der Syntax ist meiner Meinung nach etwas ungünstig - ein “new XNamespace” oder etwas ähnliches hatte nicht funktioniert. Auch ein “new XElement(’xmlns:media’,'…’)” wurde mit einer Exception belohnt - daher dieser Weg.
In der CreateElement Methode müssen wir nur noch die “media:thumbnail” + “media:content” erstellen und fertig sind wir. Zusätzlich könnte man noch die anderen Elemente des Standards einbauen - schaut einfach nochmal in den Guide.
Ergebnis:
Da wir in unserem Head immer noch den Link zum RSS Feed angegeben haben, prüft PicLens automatisch ob man die Bilder auf der “Wall” anzeigen kann:
Wer also viele Bilder auf seiner Webseite hat, könnte dies doch leicht umsetzen - insbesondere da dies ein offener Standard (Specification @ Yahoo) ist und ich davon ausgehe, dass sowas noch häufiger eingesetzt wird. Ob nun PicLens als Client ist ja am Ende auch egal
[ Download Source Code ]
PS: Als Bildquelle hab ich mal den Blog genommen - bitte aus Trafficgründen nicht überstrapazieren
ShareThis
HowTo: RSS Feeds mit LINQ to XML erstellen (XLinq)
19.06.2008 23:49:40
|
Robert Mühsig
Ein XML zu erstellen ist mit Linq to XML recht einfach - ähnliches habe ich bereits in diesem HowTo beschrieben.
Der Unterschied ist eigentlich nur in der Verwendung und in dem dynamischen anlegen der Items zu finden.
Hier erstmal der Projektaufbau:
Damit unsere Besucher auch auf den RSS Feed aufmerksam werden, hab ich noch im HEAD einen Link auf den RSS-Feed gemacht:
<head runat="server">
<title>Untitled Page</title>
<link rel="alternate" href="Rss.ashx" type="application/rss+xml" title="" id="rss" />
</head>
Die “Rss.ashx”:
Das Grundgerüst erzeugen wir direkt in der ProcessRequest Methode:
public void ProcessRequest(HttpContext context)
{
XDocument document = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("rss",
new XAttribute("version", "2.0"),
new XElement("channel", this.CreateElements())
));
context.Response.ContentType = "text/xml";
document.Save(context.Response.Output);
context.Response.End();
}
Hier wird die Deklaration gemacht und das XDocument wird in den Response.Output geschrieben. Unsere Items erzeugen wir an einer anderen Stelle - und zwar in der “CreateElements” Methode.
Die “CreateElements“-Methode:
Diese Methode gibt IEnumberable<XElement> zurück und kann somit direkt in den Baum eingefügt werden:
private IEnumerable<XElement> CreateElements()
{
List<XElement> list = new List<XElement>();
for (int i = 1; i < 100; i++)
{
XElement itemElement = new XElement("item",
new XElement("title", i),
new XElement("link", "http://code-inside.de")
);
list.Add(itemElement);
}
return list;
}
Sehr einfach und schnell gemacht
[ Download Source Code ]
ShareThis
Massenhaft Silverlight 2-Trainingsvideos in Deutsch und Englisch
19.06.2008 16:01:00
|
Steffen Ritter
Mein Kollege Oliver Scheer zeichnet momentan eine zehnteilige Einführung in Silverlight 2 als Webcasts auf. Oliver -- der auch die immer ausgebuchten Silverlight-Workshops gehalten hat, beispielsweise auf der Flashforum-Konferenz (http://www.flashforum.de/ffk08/workshops.php#Silverlight%202) oder regelmäßig für Partner und Kunden in den Microsoft-Regionalbüros (http://www.event-team.com/events/silverlightworkshop//Agenda.aspx) -- beginnt mit einer Einführung in die Werkzeuge für Silverlight und den Silverlight-Grundlagen, gibt einen ausführlichen Einblick in die XAML-Technologie, erklärt die Programmierung von Silverlight 2 in JavaScript und Managed Code -- und demonstriert natürlich den Einsatz des (unglaublich coolen, kostenlosen) Deep Zoom Composer (http://www.microsoft.com/downloads/details.aspx?FamilyID=457B17B7-52BF-4BDA-87A3-FA8A4673F8BF&displaylang=en). Abgerundet wird die Serie durch ein Kapitel zum Entwickeln eigener Controls und eine Einführung in den Expression Encoder.
Die ersten Videos von Oliver Scheer sind bereits online zum Ansehen und als Download verfügbar, der Rest kommt in Kürze: http://www.microsoft.com/germany/msdn/webcasts/serien/MSDNWCS-0806-01.mspx
Auch die Kollegen aus England waren äußerst fleißig und haben circa 50 kurze Clips zu Silverlight 2 veröffentlicht. Diese englischen Clips zeichnen sich vor allem dadurch aus, dass sie sehr kurz und knackig sind und aufgrund der thematischen Sortierung auch perfekt als kurze Nachschlagewerke dienen können. Themen sind Basics wie Layout, Controls und Data Binding, aber auch fortgeschrittene Themen wie Sockets, Cross-Domain-Anfragen, Multithreading und HTML-Interop in Silverlight. Und als wäre das nicht genug gibt es noch ein paar Kniffe für alle, die schon mehr Ahnung von Silverlight haben, beispielsweise zum dynamischen Laden von Assemblies, zur Einbettung von Schriften und für individuelle Splash Screens.
Hier wird jeder fündig, egal ob Silverlight-Einsteiger oder bereits RIA/Silverlight-Profi: http://www.miketaulty.com/SLVideos.html
Firefox 2 and 3 side by side
19.06.2008 11:08:39
|
Andre Loker
So, Firefox 3 is out. The curious part in me wants to upgrade, the reasonable part wants to stay with version 2 ("will my add-ins work with v3, yadda yadda"). Even worse, the developer in me wants to install both versions, to see how my projects work on either one. Side by side installation is not really intended by Mozilla. But luckily it's still possible.
This article will show you how you can run both FF 2 and FF 3 on the same machine. We will not change the FF 2 installation. We'll only add a non-installation version of Firefox 3 that can be launched on demand without changing the FF 2 profile. The article is based on this article and this article (German).
Before we start: I am not responsible for any trouble that this guide causes on your computer. It works fine on my machine, but don't blame me if your Firefox profile get messed up, your keyboard catches fire or your girlfriend leaves you etc.
- Make a backup of your current Firefox installation. I mean seriously, make a backup. I recommend MozBackup, it's easy yet powerful and gets its job done.
- Create a new Firefox profile for our future Firefox 3. We don't want FF 3 and FF 2 to use the same profile, so this step is important.
- Launch the profile manager with: firefox -profilemanager -no-remote
- Select "Create Profile..." to create a new profile. You can name it whatever you like (here I named it ff3test), just remember the name for later!
- Download Firefox 3 from mozilla.com. You should have 'Firefox Setup 3.0.exe' by now. Do NOT install it!
- Extract the content of 'Firefox Setup 3.0.exe' to a folder on your drive. I use 7-zip for this, but other tools may work as well. With 7-zip, right click on 'Firefox Setup 3.0.exe' and select 7-zip -> Extract to "Firefox Setup 3.0\". The folder with the extracted content should look like this:
- Remove unnecessary files: remove the following files/folders:
- optional
- removed-files.log
- setup.exe
- Move the content of localized to nonlocalized. Confirm to overwrite all files when asked. You can delete the "localized" folder safely.
- The "nonlocalized" folder now contains all required FF 3 binaries. You may rename it (to let's say "Mozilla Firefox 3") and move it (to "Program Files (x86)") if you like.
- Create a shortcut to FF 3. In this example I create a shortcut on my desktop.
- Locate firefox.exe in the (former) "nonlocalized" folder, right click on it, choose 'Send to' -> 'Desktop'
- Locate the shortcut on your desktop, rename it if you like, right click it and choose 'Properties'
- Append "-P ff3_profile -no-remote" to the "Target" text field, where ff3_profile is the name of the designated Firefox 3 profile you created in step 2. In my case it was called "ff3test", so my text field looks like:
That's it! You can now continue to use FF2 as usual. If you feel like FF3'ing, just use the shortcut we created to run the shiny new Firefox 3. Of course, there is no uninstall option for FF 3 (we did not install it in the first place). To get rid of FF3 just delete the respective folder, the shurtcut and if necessary the profile.
NB: the first time you start FF2 after this procedure the profile manager may appear. Just select the default profile and check "Dont's ask at startup".
Virtual Earth + Silverlight Deepzoom
19.06.2008 07:59:42
|
Robert Mühsig
Im Blog von Chris Pendleton (Virtual Earth Tech Evangelist) bin ich auf ein paar interessante Kombinationen von Silverlight und Virtual Earth gestoßen.
Genauer gesagt, geht es um die “Deepzoom” Funktionalität, hier ein (etwas ruckliges) YouTube Video:
“DeepEarth” ist gehostet auf Codeplex und kann auch hier live angeschaut werden.
Etwas cooler gemacht ist der “Silverlight Map Viewer” von IDV Solutions (allerdings ohne Source Code).
Fazit: Ziemlich cool
PS: Im Blog von Chris tauchte auch die Frage auf, warum MS sowas nicht selber anbietet - einfach mal die Kommentare durchlesen.
ShareThis
Windows Vista - Beide Prozessoren bzw. Kerne beim Bootvorgang benutzen
18.06.2008 23:58:00
|
Peter Bucher
Gerade eben bin ich auf ein nettes HowTo-Video gestossen, Zitat:
In diesem VideoTutorial wird gezeigt, wie Sie Windows Vista so einstellen können, dass beim Bootvorgang alle bzw. mehrere Prozessoren genutzt werden. Auch wenn Sie einen Dual- oder Mehrcore-Prozessor besitzen, ist Vista standardmäßig so eingestellt, dass nur ein Prozessor genutzt wird.
Naja, da fragt sich manch einer doch: Wieso ist das nicht standardmässig immer auf das höchste eingestellt?
PS: Ob es was bringt, sehe ich beim nächsten Booten ;-)
PPS: Geht natürlich auch für Windows Server 2008.
WPF: Layout-System und Performance
18.06.2008 18:26:40
|
Norbert Eder
Müssen viele Elemente erstellt und dargestellt werden, kann die Performance schon mal sehr schnell in den Keller gehen. Dabei müssen die darzustellenden Elemente keineswegs komplex sein. Vielmehr reichen oft kleine Fallen, die vermieden werden wollen.
Oftmals führt das Verwenden eines
falschen Panels zu einem Performance-Problem. Meist ist es so, dass genau das Panel verwendet wird, welches die gewünschte Aufgabe mit dem geringsten Aufwand (für uns als Entwickler) erfüllt. So wird also beispielsweise ein StackPanel verwendet, sollen Elemente untereinander platziert werden - und zwar in der Reihenfolge, wie sie hinzugefügt wurden. Werden ein paar wenige Elemente hinzugefügt, ist keine Auswirkung zu spüren. Sind es hunderte oder gar tausende, dann wird dieser Vorgang spürbar langsamer.
Hierfür verantwortlich ist die unterschiedliche Funktionalität der Panels. Während ein Canvas relativ
dumm ist und Elemente basierend auf einer Positionsangabe platziert, ist diese Logik in einem StackPanel oder einem DockPanel wesentlich komplexer.
Layout System
Vom Layout-System werden pro Kindelement zwei Schritte durchgeführt:
Jedes dieser Kindelemente besitzt seine eigene Implementierung von Measure und Arrange, damit die an das Element gestellten Anforderungen bezüglich des Layout-Verhaltens erfüllt werden können.
Ablauf Layouting
- Ein Kindelement (UIElement) beginnt den Layoutprozess durch das Erfassen der Basiseigenschaften
- Dann werden die Eigenschaften bezüglich Höhe, Breite, Randstärke ausgewertet
- Ausführung von Panel-spezifischer Logik (siehe Orientation-Eigenschaft des StackPanels)
- Der Inhalt wird ausgerichtet bzw. positioniert, nachdem die Größe etc. aller Kindelemente bemessen wurde.
- Die Liste der Kindelemente wird am Bildschirm ausgegeben
Wann wird es haarig?
Beim Eintreten bestimmter Aktionen, wird der gesamte Layout-Prozess erneut durchlaufen. Folgende Aktionen sind dafür maßgeblich:
- Hinzufügen eines neuen Kindelementes
- Ausführung der Methode UpdateLayout eines Kindelementes
- Zuweisung von LayoutTransform eines Kindelementes
- Bei Änderung einer Dependency Property mit Auswirkung auf Measure und Arrange (gesetzt über die Metadaten)
Fazit
Durch das Wissen wie das Layout-System funktioniert und wann es erneut durchlaufen werden muss, lässt sich feststellen, in welchen Fällen worauf verzichtet werden sollte. So kann es beispielsweise effizienter sein, eine ListBox anstatt eines StackPanels zu verwenden (durch das Definieren von Templates kann das auch schön aussehen), oder vielleicht doch einen Canvas.
Ist man sich nicht sicher, ob die geplante Variante die beste Performance bietet, bietet sich auch an, vor der konkreten Implementierung dann eventuell doch eine kleine Beispielanwendung zu schreiben. Auch eingesetzte Profiler sind hilfreich.
Siehe auch:
WPF: Performance messen und verbessern
Ungünstige Performance bei Contains in LINQtoSQL
18.06.2008 16:47:17
|
Thomas Schissler
In einem Projekt nutze ich Contains um eine Liste mit IDs zu übergeben, um dann Objekte
per LINQtoSQL aus der Datenbank zu lesen. Das klappt wunderbar, solange die Liste
mit den IDs nicht zu groß wird. Bei knapp über 1000 IDs hatte ich allerdings ca. 5
Sek. für die Ausführung was mir dann doch recht lange vorkam. Ich habe mir dann mal
mit dem SQL Profiler angeschaut, was LINQ da eigentlich treibt und hatte dann schnell
eine Vermutung. LINQtoSQL ruft an der stellen nämlich eine Stored Procedure auf und
übergibt die IDs als Parameter dort hin, d.h. über 1000 Parameter deklarieren und
zuweisen, das könnte dauern. Ich habe das Statement dann testhalber einfach umgebaut,
dass ich im SELECT direkt die IDs über ein IN(...) angab und siehe da, diese Abfrage
war nun um Dimensionen schneller.
Merke: Über Contains keine große Anzahl von Parametern übergeben, statt dessen lieber
die Abfrage selber mit einem IN aufbauen.
Deutsche Testversionen von Expression Studio 2 ab sofort verfügbar
18.06.2008 14:21:00
|
Steffen Ritter
Die deutschen Testversionen von Expression Studio stehen ab sofort als kostenlose Downloads bereit: http://www.microsoft.com/downloads/results.aspx?DisplayLang=de&nr=20&productId=C0037913-9E11-4A2D-8FD1-0BA441296CBC&freetext=Expression&sortCriteria=date
<Marketing Copy>Microsoft Expression Studio 2 ist die neue Familie professioneller Werkzeuge für Webdesigner, Interactive Designer und Entwickler von Rich Internet Applications. Designer erhalten mit Expression Studio das perfekte Komplettpaket zum Entwerfen von standardkonformen Websites, Benutzeroberflächen von Windows-Anwendungen und plattformübergreifenden Webanwendungen mit Microsoft Silverlight – so einfach, sicher und schnell wie nie zuvor. </Marketing Copy>
Expression Studio 2 ist in Deutschland ab 7. Juli im Handel.
Speed up Firefox when using Development Server
18.06.2008 13:17:28
|
Andre Loker
The problem
Using Firefox on Vista to view websites hosted by the Visual Studio Development Server can be unbearably slow. Pages take aeons (i.e. several seconds) to load while viewing the same site under IE does not suffer from this issue.
The solution
As mentioned in this blog post, this problem can be solved like this:
- Open the Firefox config (browse to about:config)
- Locate the setting: network.dns.disableIPv6 (type "v6" into the filter field)
- Change the value to true (double click the row)
The result
Now sites on the built in development server work fast even under Firefox and Vista.
The conclusion
What can I say - it works :-)
Update 06/19/2008: works with Firefox 3 as well
LAN-Scan, aber richtig schnell! Teil - 3
17.06.2008 20:47:42
|
Klaus Bock
Wie im vorherigen Artikel angesprochen, will ich dieses mal die Klasse ClientList, welche die Ergebnisse des Scans speichert, vorstellen. Zunächst galt es ein Basiselement festzulegen welches mehre Datenreihen, jede Reihe bestehend aus verschiedenen Datentypen, speichert und dabei noch leicht zu handhaben ist. Von eigenen Konstrukten bin ich schnell abgerückt und habe mich für die DataTable entschieden. Sie besitzt alle notwendigen Eigenschaften die ich benötige:
- sie ist serialisierbar, zur Verwendung mit anderen Prozessen
- den Export der Ergebnisse im XML-Format gibt es gratis dazu
- sie besitzt mit dem DataTableReader einen schnellen und einfachen Vorwärts-Cursor
- das jeweilige Ergebnis kann, in Form einer DataRow, an der Position des Cursors eingefügt oder ersetzt werden.
Einziger Wermutstropfen ist das Einfügen einer DataRow in Multithread-Anwendungen. Zitat MSDN:
Dieser Typ ist bei Multithread-Lesevorgängen sicher. Sie müssen alle Schreibvorgänge synchronisieren.
Doch dazu später mehr.
Als erstes werden die Namen und der Datentyp der jeweiligen Spalte festgelegt. Benötigt wird hier: die IP-Adresse, der Hostnamen und der Online-Status eines jeden LAN-Client. Der Einfachheit halber habe ich mich entschieden die IP-Adresse als Zeichenfolge zu speichern, der Hostnamen ist sowieso eine Zeichenfolge und der Online-Status wird als boolscher Wert abgelegt. Da ich auf die DataTable in der ganzen Klasse zugreifen will, wird sie als Class Member instanziiert um im Konstruktor initialisiert und auch gleich das Schema festgelegt:
public ClientList()
{
// Mutex initialisieren
this.mutex = new Mutex(false);
// neue DataTable erzeugen und das Schema festlegen
this.table = new DataTable("Clients");
this.table.Locale = CultureInfo.CurrentCulture;
this.table.Columns.Add("IpAddress", typeof(string));
this.table.Columns.Add("Name", typeof(string));
this.table.Columns.Add("Online", typeof(bool));
}
So ist gewährleistet, dass bei der Instanziierung der Klasse die DataTable immer richtig erzeugt wird.
Da ich aber nicht nur Daten anfügen will sondern sich der Online-Status eines Clients bei einem wiederholten Scan geändert haben kann, muss es auch die Möglichkeit geben Daten zu ersetzen. Leider bietet die DataTable keine Möglichkeit dazu. Doch mit einem kleine Kniff ist auch das zu lösen. Die DataTable bietet über die DataRowCollection die Methoden RemoveAt(int index) und InsertAt(DataRow row, int pos). Nacheinander ausgeführt hat man auch eine Update-Methode.
// da keine Update-Methode zur Verfügung steht,
// Reihe erst löschen und am selben Index einfügen
this.table.Rows.RemoveAt(i);
this.table.Rows.InsertAt(row, i);
Nachdem die Handhabung der Daten in der DataTable geklärt ist, steht noch die Threadsicherheit aus. Als Mechanismus zur Synchronisierung habe ich nicht die lock-Anweisung gewählt, sondern mich für die Verwendung eines Mutex entschieden. Aus meiner Sicht ist der Mutex ein sehr flexibles Werkzeug und lässt sich auch in einem Fehlerfall noch sehr gut handhaben. Ein zweiter wichtiger Punkt ist die Möglichkeit, für eine spätere Erweiterung der Klasse, den Mutex als systemweiten Mutex in einer Eigenschaft nach außen verfügbar zu machen und als WaitHandle zu nutzen. Der entscheidende Punkt für mich war jedoch die Möglichkeit bei einem Threadfehler, z.B. wenn ein Thread in der Bearbeitung abgebrochen wird der gerade den Mutex besitzt, diesen Fehler abzufangen und den Mutex noch freigeben zu können. Nach dem ein Thread beendet oder abgebrochen wurde der gerade im Besitz des Mutex war, geht der Mutex auf den nächsten Thread in der Warteschlange über. In diesem nächsten Thread wird eine AbandonedMutexException ausgelöst, auf die reagiert werden kann. Ich verwende in der ClientList Klasse die Eigenschaft AddedSuccessfull die der aufrufenden Methode signalisiert ob das Ergebnis in die DataTable geschrieben werden konnte. Diese Eigenschaft gibt die private Member Variable addedSuccessfull zurück. Diese private Variable wird mit dem Schlüsselwort volatile instanziiert um zu gewährleisten, dass auch wirklich der letzte zugewiesene Wert der Variablen zurückgegeben wird. Im try-catch Block wird nun im catch diese Variable auf false gesetzt und somit der aufrufenden Methode signalisiert, dass die Daten nicht geschrieben werden konnten. Hier ein Beispiel:
try
{
// aktuellen Thread blockieren um
// sicher die Daten in der DataTable zu bearbeiten
this.mutex.WaitOne();
// weiterer Code
}
catch (AbandonedMutexException)
{
this.addedSuccessfull = false;
}
finally
{
// Mutex auch im Fehlerfall freigeben
this.mutex.ReleaseMutex();
}
Somit kann sichergestellt werden, dass die Ergebnisse auch wirklich sauber geschrieben werden. Zumindest solange, bis jemand den Gegenbeweis antritt. Für interessierte füge ich hier noch als letztes Listing die komplette Klasse an. Die XML-Kommentare habe ich noch nicht erstellt, aber davon abgesehen sollte die Klasse komplett sein.
internal class ClientList : IDisposable
{
#region Fields
/// <summary>
///
/// </summary>
/// <remarks></remarks>
private volatile bool addedSuccessfull;
/// <summary>
///
/// </summary>
/// <remarks></remarks>
private bool disposed;
/// <summary>
///
/// </summary>
/// <remarks></remarks>
private Mutex mutex;
/// <summary>
///
/// </summary>
/// <remarks></remarks>
private DataTable table;
#endregion Fields
#region Constructors
/// <summary>
///
/// </summary>
/// <remarks></remarks>
public ClientList()
{
// Mutex initialisieren
this.mutex = new Mutex(false);
// neue DataTable erzeugen und das Schema festlegen
this.table = new DataTable("Clients");
this.table.Locale = CultureInfo.CurrentCulture;
this.table.Columns.Add("IpAddress", typeof(string));
this.table.Columns.Add("Name", typeof(string));
this.table.Columns.Add("Online", typeof(bool));
}
#endregion Constructors
#region Public Properties
/// <summary>
///
/// </summary>
/// <value></value>
/// <remarks></remarks>
public bool AddedSuccessfull
{
get { return this.addedSuccessfull; }
}
/// <summary>
///
/// </summary>
/// <value></value>
/// <remarks></remarks>
public DataTable ClientTable
{
get
{
return this.table;
}
}
#endregion Public Properties
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="disposing"></param>
/// <remarks></remarks>
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
this.table.Dispose();
this.mutex.Close();
}
}
this.disposed = true;
}
#endregion Private Methods
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="name"></param>
/// <param name="online"></param>
/// <exception cref="T:System.ArgumentException">
///
/// </exception>
/// <exception cref="T:System.ObjectDisposedException">
///
/// </exception>
/// <remarks>n/a</remarks>
public void AddOrReplace(string ipAddress, string name, bool online)
{
// prüfen ob Dispose bereits ausgeführt wurde
if (this.disposed)
{
throw new ObjectDisposedException("ClientList");
}
this.addedSuccessfull = false;
// ip-String auf Gültigkeit prüfen
if (!IPHelper.ValidateIP(ipAddress))
{
throw new ArgumentException("Die übergebene Zeichenfolge ist keine gültige IP-Adresse.");
}
try
{
// aktuellen Thread blockieren um
// sicher die Daten in der DataTable zu bearbeiten
this.mutex.WaitOne();
// neue DataRow zum Anfügen oder Ersetzen initialisieren
DataRow row = table.NewRow();
row[0] = ipAddress;
row[1] = name;
row[2] = online;
// Index initialisieren
int i = 0;
// prüfe ob die DataTable bereits Elemente enhtällt
if (this.table.Rows.Count > 0)
{
// neuen DataTableReaser mit der lokalen DataTable initialisieren
DataTableReader reader = new DataTableReader(this.table);
// durch die DataTable itterieren
while (reader.Read())
{
// IP-Adressen vergleichen
if (string.Equals(reader.GetString(0), ipAddress, StringComparison.Ordinal))
{
// IP-Adresse ist vorhanden
// prüfe ob Änderungen in der Reihe
if (!string.Equals(reader.GetString(1), name, StringComparison.OrdinalIgnoreCase)
|| reader.GetBoolean(2) != online)
{
// da keine Update-Methode zur Verfügung steht,
// Reihe erst löschen und am selben Index einfügen
this.table.Rows.RemoveAt(i);
this.table.Rows.InsertAt(row, i);
// signalisieren, dass die DataTable erfolgreich bearbeitet wurde.
this.addedSuccessfull = true;
// Reihe ersetzt, beenden
return;
}
else
{
// signalisieren, dass die DataTable erfolgreich bearbeitet wurde.
this.addedSuccessfull = true;
// keine Änderung, beenden
return;
}
}
// Index erhöhen
i++;
}
}
// DataRow anhängen
this.table.Rows.Add(row);
// signalisieren, dass die DataTable erfolgreich bearbeitet wurde.
this.addedSuccessfull = true;
}
catch (AbandonedMutexException)
{
this.addedSuccessfull = false;
}
finally
{
// Mutex auch im Fehlerfall freigeben
this.mutex.ReleaseMutex();
}
}
/// <summary>
///
/// </summary>
/// <remarks>n/a</remarks>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion Public Methods
}
Parallel Ping Tests
Firefox 3 - erster Eindruck
17.06.2008 20:23:53
|
Robert Mühsig
Firefox 3 ist heute erschienen. Natürlich hab ich ihn gleich mal runtergeladen.
Mein erster Eindruck: Nett, nichts weltbewegendes. Schneller auch nicht wirklich (bzw. kann ich es jetzt noch nicht direkt sagen, allerdings funktioniert bei mir erstmal die personalisierte Windows Live Seite nicht
)
Die Installation ging ohne Probleme, allerdings gehen momentan nicht alle Addons:
Erster Gedanke als Firebug nicht aktiviert war: “Och nö…”
Ansonsten ist das ein oder andere Feature ganz nett - ich denke auch, dass die Plugins nachziehen werden.
Daher Fazit: Solange IETab und Firebug nicht geht, wird er nicht auf meinem Arbeitsrechner installiert werden.
ShareThis
Wöchentliche Rundablage: Ab jetzt bei Del.icio.us
16.06.2008 23:01:31
|
Robert Mühsig
Die “Wöchentlichen Rundablagen” wurden von mir eingeführt um das, was ich in der Woche so sinnvolles fand, irgendwo zu hinterlegen. Leider “verstopfen” sie etwas die Suchresultate auf dem Blog und auch die Übersicht lässt stark zu wünschen übrig.
Daher habe ich mich nun (mal wieder) bei del.icio.us angemeldet.
Das Management:
Die del.icio.us Seite ist natürlich nett, allerdings will ich lieber meine “Bookmarks” im Firefox managen, dazu gibt es ein Tooles Plugin - das del.icio.us Firefox Plugin, hier mal ein paar Screenshots:
“Tagging Management”
Hinzufügen eines neuen Bookmark:
Sehr schönes tagging.
Del.Icio.us Wordpress Integration:
Damit die Links trotzdem irgendwo auf dem Blog auftauchen, habe ich einfach diesen kleine HTML Snippet eingefügt. Das Ergebnis ist folgendes:
Sehr viele Links direkt aus meiner “Rundablage”.
Ich hoffe das macht den Blog übersichtlicher
Das ist somit der letzte “Wöchentliche Rundablage” Post.
ShareThis
I lost my first hard drive
16.06.2008 14:25:11
|
Andre Loker
Today for the first time I lost a hard drive. I mean literally: I lost it. Several weeks ago I removed it from a computer and I can't remember where I put it. Gotta spend my time searching for it now instead of doing something productive.
Gosh, it's Monday again :-(
Update: I found it. It was already plugged into another computer. I can't remember to have put it there, though...
Keep your .config clean with external config files
16.06.2008 13:25:27
|
Andre Loker
The web.config (or app.config for non-web applications) file is the central place to configure your web application, starting from connection strings, over application settings to ASP.NET specific topics like caching, authentication & authorization, sessions as well as HTTP handlers and modules. Normally the web.config starts as a neat little pet you can easily manage. But as soon as your project grows mature, web.config turns out to be a huge beast. The size itself is often not that much of a problem. An issue I personally find more important is the fact that I need my web.config files to be different for my developer's machine and the deployment scenarios: on my dev machine I certainly have different connection strings than on the production server, the same counts for app settings, logging, compilation settings etc. pp.
Maintaining multiple configuration files is a PITA, especially when it comes to the configuration parts that have to be similar on all config files (e.g. http handlers and modules will most likely be the same).
Luckily the .NET configuration system has a feature that drastically lightens the burden for us. Each configuration section may define an attribute named "configSource" to define an alternate location from where the configuration has to be loaded. Let's have a look at an example.
In web.config locate or create the connectionStrings section. Remove all child elements (<add>, <remove> or <clear>) and add a new attribute named configSource. Give it the name of a file called "ConnectionStrings.config" as its value:
<connectionStrings configSource="ConnectionStrings.config"/>
Add a new file called "ConnectionStrings.config" to the same directory where web.config lives and define its content as follows:
<?xml version="1.0"?>
<connectionStrings>
<add name="MyDB" connectionString="Data Source=myServerAddress;Initial Catalog=MyDataBase;Integrated Security=SSPI;"/>
</connectionStrings>
That's it. Now the content of ConnectionStrings.config will be used for the connectionStrings section.
Some things to note:
- The external configuration file must contain the section's name as the root element, i.e. an external config file for the <smtp> element must have the <smtp> node as it's root even though the element is nested within system.net/mailSettings in the original web.config.
- If you use configSource you must not define any other attribute or child element for the respective section in web.config. This means that configSource can never be used to add additional content to a section. It will always replace the section.
- It might be useful to move configuration files to a subfolder to keep the root directory clean. I personally use a subfolder named Config. The configSource attributes have to include the folder in that case, like configSource="Config\connectionStrings.config"
- The actual file extension of the external configuration files does not matter (as long as you point to the correct file in the configSource attribute). Keep in mind, though, that depending on the extension the web server might or might not serve the literal content of the config files when requested. If the config files contain sensitive information (DB passwords etc.) this can be a massive security risk. .config is one of the extensions IIS/ASP.NET will refuse serve to the client. Therefore I recommend to always give configuration files the extension ".config".
Multiple deployment scenarios
Now that we are able to move configuration settings to an external source file the web.config becomes easier to manage: if for example we need to have two different sets of connection strings (or app settings etc.) for different deployment scenarios we can define multiple external configuration files, each one for a different scenario, like: connectionStrings-dev.config for my dev machine and connectionStrings-deploy.config for the production server. All I have to do to switch between these two is to modify the configSource in the web.config. (BTW: the web deployment projects can do this automatically for you, just check the "Enable Web.config file section replacement" checkbox under the "Deployment" tab and define the new file names; see Extreme ASP.NET: Web Deployment Projects under "Pluggable Configuration Files").
Hiding sensitive information
If you're working on an open source project that uses a shared code repository you may not want specific information to appear in the repository, like database connection strings, smtp credentials. If you move those settings to external configuration files it is easy to exclude them from your repository.
Non-standard config sections
ConfigSource is a feature of the .NET configuration system and not specific to the ASP.NET configuration sections. Therefore it should work with other config sections as well.
Recommendations
Personally I recommend to move the following sections to external configuration files:
- appSettings - likely to change for different deployment scenarios
- connectionStrings - likely to change for different deployment scenarios
- smtp in system.net/mailSettings - for security reasons and because it's likely to change for different deployment scenarios
- machineKey in system.web - primarily for security reasons
- External libraries like log4net, Castle Windsor, NHibernate etc
Flackern bei WPF Anwendungen und Aero Style
16.06.2008 12:20:00
|
Jens Peter Kleinau
In meinem vermutlich unverdienten aber doch sehr schönen Urlaub erreichte mich folgende Frage per Mail, aus der ich den Kern hier frei zitiere:
Bei einer WPF Anwendung flackert der Hintergrund des Fensters beim Resizen (Vergrößern oder Verkleinern mit der Maus am Fensterrand) sobald der Aero Style von Vista eingeschaltet ist. Das gleiche Flackern passiert, wenn ein WPF Control in eine...
[[ This is a content summary only. Visit my website for full links, other content, and more! ]]
Power to the Tools - die Open XML PowerTools
16.06.2008 10:37:51
|
Jens Häupel
Nun gibt es ein weiteres cooles Open Source Project, die PowerTools for Open XML. Das Erzeugen, Ändern und Umwandeln von Open XML Dokumenten auf dem Server wird dadurch erheblich erleichtert. In den PowerTools gibt es Beispiele und Anleitungen, wie mit Hilfe von Commandlets für PowerShell Open XML Dokumente bearbeitet oder erzeugt werden können
Beispiele: automatisierte Word bzw. Excel Dokument-Generierung, Vorbeireitung von Dokumenten für die externe Weiterleitung (incl. Kommentare entfernen, Änderungen annehmen, einheitliche Themes anwenden bzw. Wasserzeichen setzen).
Die PowerTools basieren auf dem Open XML SDK und benötigen kein Office 2007 zum funktionieren, also keine COM Automation mehr.
Auf Eric White's Blog gibt es ein kurzes Übersichtsvideo und weitere Infos dazu.
Open XML SDK v1 released
16.06.2008 10:26:35
|
Jens Häupel
HowToCode "ReadYou": Von Accounts & IDs - das Usersystem
15.06.2008 23:56:26
|
Robert Mühsig
Fast jede Anwendung die heute irgendwie läuft, benötigt ein Login oder man kann bestimmte Profildaten anhäufen etc. Daher ist das Usersystem die erste große Hürde, die es zu überwinden gilt.
Solch ein Usersystem ist prinzipell recht schnell gemacht, allerdings muss das Usersystem laut den Anforderungen auch andere Provider (wie OpenID, Windows Live ID etc.) unterstützen.
Im Mittelpunkt steht der “User” - in dem Fall ein ganz normaler Nutzer unser Applikation. Ein “User” kann mehrere “Identitäten” haben, z.B. eine Windows Live ID, eine OpenID oder auf ein eigenes Login-System setzen. Ob ich das später tatsächlich einbaue ist eine andere Sache, allerdings sollte das System möglichst “offen” sein.
Dann hat natürlich unser “User” “Accountdaten” (also Profildaten etc.) die wir in unserer Applikation brauchen - die könnte man später z.B. über bestimmte Connectoren befüllen - das ist aber nur eine fixe Idee.
Diese Accountdaten werden momentan durch diese recht einfache Userklasse repräsentiert:
Das “Problem” der Zuordnung
Mein selbst festgelegtes Ziel hat natürlich ein Haken: Ein User hat mehrere Identitäten - eine eindeutigen Namen brauch ich also, um genau zu sagen, dass Nutzer A der sich gerade mit seiner Windows Live ID anmeldet auch wirklich Nutzer A ist.
Dafür ist in der User-Klasse der “AccountName” vorgesehen - ein eindeutiger Name der zu beginn vom Nutzer festgelegt wird.
Die “ID” (eine GUID) wird in dem Falle vielleicht nicht mehr benötigt, allerdings könnte ja noch die Anforderunge rein kommen, dass jemand seinen Nutzernamen ändern möchte - daher die “ID“.
Der “IdentificationName” ist der Name, mit dem der User sich gerade angemeldet hat, also wenn er z.B. seine OpenID angegeben hat, steht da “http://user.myopenid.com” da.
Ablauf der Anmeldung / Registrierung
1. User registriert sich mit einer beliebigen Identifikation (”IdentificationName”) und einem Nickname (”AccountName”)
2. User wird im System angelegt und in einer Zuordnungstabelle wird festgehalten, das User A mit der Identifikation A sich anmelden darf.
3. User meldet sich ab.
4. User meldet sich wieder mit seinem “IdentificationName” und dem dazugehörigen Passwort an (seinem OpenID-Passwort z.B.)
5. In der Zuordnungstabelle wird überprüft, ob User X sich mit der ID überhaupt anmelden darf, wenn ja, dann ist er eingeloggt.
6. Wenn er eingeloggt ist, darf er seine Accountdaten weiter pflegen.
Identification-Interface
Momentan ist das Interface noch recht “klein”:
Ein Fall fürs Prototyping
Da ich momentan doch noch recht unsicher über das Design bin, werde ich erstmal ein paar Provider “prototypen”, sodass ich sehen kann, ob es überhaupt so machbar wäre.
Fazit & Feedback
Code gibt es heute leider nicht zu sehen, zwar läuft bereits ein UnitTest erfolgreich durch, allerdings muss mal ein, zwei “richtige” Loginsysteme integrieren um eine schlüssige Aussage machen zu können.
Wie immer gilt: Feedback ist gern gesehen - wenn ihr sagt, dass ich mich hier total irre oder etwas wichtige übersehe, dann nur zu
Ich bemüh mich in dieser Woche ein Login-System auf die Beine zu stellen. Wenn dies erstmal steht schauen wir weiter
ShareThis
WorldWide Telescope & Backchannel-Diskussion
15.06.2008 22:11:00
|
Lori Grosland
Vor ein paar Jahre war ich auf Hawaii – the Big Island – und bin da auf dem Vulkan Mauna Kea Sterngucken gegangen. Was ich da oben gesehen habe, war unglaublich und fast unbeschreiblich. Die Sterne, die Milchstraße war so klar und so schön. Wenn man in einer großen Stadt wohnt, hat man wenige Möglichkeiten die Sterne wirklich zu betrachten, wie ich auf Mauna Kea gesehen habe. Seit einem Monat habe ich ein neues „Spielzeug“ entdecket, das erlaubt mich die Sterne näher zu betrachten ohne nach Hawaii zu fliegen müssen. WorldWide Telescope ist ein kostenloses Tool das ermöglicht uns, eine virtuelle Reise durch das Universum zu erleben und das Weltall von einem PC zu entdecken und zu erforschen. Auch wenn die Sterne auf Hawaii sehr schön anzuschauen waren, habe ich nicht die Möglichkeit gehabt, mehr über das Universum zu lernen. Aber jetzt kommt das Projekt WorldWide Telescope und macht es einfacher für uns alle über das Weltall und Astronomie zu lernen.
WorldWide Telescope ist ein Projekt von Microsoft Research und hat ein sehr leicht zu bedienendes User-Interface und hat Terabytes von Bilder und Daten. Es basiert auf der "Visual Experience Engine", die das nahtlose hinein- und heraus- zoomen aus den Bildern ermöglicht. Für die Darstellung von dem Universum werden Bilder aus Observatorien verwendet, die sich auf der ganzen Erde sowie im All befinden. Mann kann das Sonnensystem und Galaxien durchstöbern oder an geführten Touren teilnehmen, die von Astronomen oder Lehrenden großer Universitäten und Planetarien angeboten werden. Wir können auch auswählen, durch welches Teleskop wir alles schauen möchten: wie z. B. das Hubble Space Teleskop, das Chandra X-Ray Observatory Center oder das Spitzer Space Teleskop. Es gibt auch die Möglichkeit die Stellung bestimmter Planeten – in der Vergangenheit, heute und in der Zukunft – zu verfolgen oder das Universum auf unterschiedlichen Wellenlängen des Lichts zu bereisen. Es gibt auch die Möglichkeit ein Teleskop mit einem USB-Anschluß zum WorldWide Telescope anzuschließen und eine Betrachtungsliste (observation list) zu verfolgen.
Mehr Information zu WorldWide Telescope und um die Software downzuloaden finden Ihr hier: http://www.worldwidetelescope.org
Backchannel Diskussion – Online Chat
Bist Du ein Blogger und begeisterte Hobby-Astronomen? Oder würdest gern die Chance haben, mit den Leuten, die WorldWide Telescope gebaut haben, zu chatten? Am 17. Juni gibt eine Online-Chat für Bloggers mit WorldWide Telescope Lead Researcher Curtis Wong und Lead Developer Jonathan Fay. Bloggers weltweit wird an dieser Online-Diskussion teilnehmen und es wird ein Audio und Video-Feed geben. Wenn Du ein Blogger bist und Lust hast, dabei zu sein, kontaktiere mich per Email oder schreibe ein Kommentar auf meinem Blog. Ich bin auch via XING oder Twitter erreichbar. :-)
SQL Server Performance Tips - Initial Datenbankgrösse - Initial Database Size - sp_helpdb
15.06.2008 16:46:00
|
Ozgur Aytekin
Es sind diverse Faktoren, warum der Performance einer Datenbank mit der Zeit immer mehr abnehmen kann.
Einer von diesen Faktoren kann vom Anfang an unterdrückt werden, in dem die Default-Werte (Default values) der Datenbankgröße (Database size) bei der Erstellung einer Datenbank definiert werden.
Eine Datenbank auf einem SQL Server erstellen ist wirklich keine großer Hexerei mehr. Einfach Microsoft SQL Server Management Studio starten und dann den SQL Server Instanz wählen. Anschließend über das Kontextmenü New Database
Eine Datenbank auf einem SQL Server erstellen ist wirklich keine großer Hexerei mehr. Im Microsoft SQL Server Management Studio den SQL Server Instanz bestimmen und über Kontextmenü den Befehl New Database auswählen.
Im New Database-Dialog kann der Datenbankname (Database name) eingegeben und dann mit OK-Button die Datenbank erstellt werden. So einfach wird eine Datenbank auf einem SQL Server erstellt.
Genau an dieser Stelle kann der Initialgröße (Initial Size) einer Datenbank definiert werden. In diesem Beispiel sind die Initial Size Angaben mit 2 und 1 Mbyte definiert. Mit dieser Initial Size-Angaben wird für die Datenbank eine MDF (Data) mit der Größe von 2 Mbyte und eine LDF (Log)-Datei mit der Größe von 1 Mbyte erstellt.
Die Eigenschaft Autogrowth besitzt die Default-Werte von 1 Mbyte bei Data-Datei und 10 Prozent bei Log-Datei. Mithilfe dieser Eigenschaft wird festgelegt, bei, wie viel Mbyte die Dateien vergrößert werden soll.
In diesem Beispiel wird die Data-Datei um 1 Mbyte vergrößert. Und wenn die Daten-Größe 3 Mbyte erreicht wird, dann wird dieser Datei wieder um 1 Mbyte vergrößert.
Die automatische Vergrößerung der Data- oder Log-Dateien können die Performance der Datenbank negativ beeinflussen. Dieser Faktor muss bei der Datenbank mit hoher Datenzuwachsrate unbedingt geändert werden, damit die Abstände zwischen den Vergrößerungsaktionen größer sind.
Bei einer Datenmigration von einer anderen Datenbank in einer SQL Server Datenbank sollen die Initial Size-Angaben angepasst werden. Die Größe der Quell-Daten kann für die Initial Size-Eigenschaft der Data-Datei als Initial-Wert definiert werden. So erstellt der SQL Server vom Anfang an eine genügend große Data-Datei und die größer dieser Datei muss während der Datenübernahme vom SQL Server nicht immer wieder vergrößert werden.
Mit Hilfe von sp_help Stored Procedure kann die Größe der Data und Log-Dateien einer Datenbank ermittelt werden.
EXEC sp_helpdb N'SampleDatabase';
sp_helpdb liefert für die angegebene Datenbank folgende Informationen:
name: Datenbank-Name
db_size: Die Datenbankgrösse in MB
owner: Den Besitzer der Datenbank
dbid: Interne ID der Datenbank
created: Erstellungsdatum
status: Im Feld Status sind verschiedene Informationen wie aktuller Status, ob der Datenbank nur lesen oder lesen-schreibend verfügbar, ist vorhanden.
compatibility_level: Kompatibilitäts-Level der Datenbank (SQL Server 2000 = 80, SQL Server 2005 = 90 usw.)
Im zweiten Result-Set werden die Angaben pro Datenbank-Datei (MDF und LDF) aufgeführt:
name: Logischer Dateiname
fileid: Interne ID der Datei
filename: Physischer Datei-Pfad und –Name
filegroup: Mit dieser Information wird die Datei-Gruppe angegeben. Bei Log-Dateien ist dieser Angabe NULL.
size: Aktueller Dateigrösse in KB
maxsize: Maximal erlaubter Dateigrösse
growth: Um wie viel der Datei vergrössert wird
usage: Für was dieser Datei benutzt wird. Daten = data only und Log = log only.
Für weitere und detaillierte Informationen kann ich folgenden URL empfehlen:
SQL Server 2005 Books Online - sp_helpdb (Transact-SQL)

Mausfrei für eine Woche, oder: Home, End und Konsorten
13.06.2008 21:55:00
|
Peter Bucher
Ich arbeite schon relativ lange mit PCs, aber die Tasten [Home] und [End] habe ich bisher nicht wirklich benutzt.
Letztens habe ich sie entdeckt und ganz bewusst genutzt.
Was soll ich sagen: Einfach nur genial :-)
In Verbindung mit den Tasten [PgUp] und [PgDn] (PageUp und PageDown) lässt es sich super ohne Maus im Code / Text navigieren.
Ich denke das ich mir mal eine Woche ohne Maus gönne, um noch mehr Navigations- und Optionsmöglichkeiten aus der Tastatur rauszuholen und anzugewöhnen.
Wenn dann mal keine Maus zur Verfügung stellt, ist man immer noch schnell und wenn es gut läuft, geht es nur mit der Tastatur noch schneller als mit der Maus kombiniert.
Natürlich ist die Maus für gewisse Anwendungen viel komfortabler und kann aus der Heutigen Zeit nicht mehr weggedacht werden.
Ausserdem hält eine Maus so auch länger (-:
Aber ich denke so eine Woche Mausfrei (Natürlich Privat :-) würde jedem gut tun.
Wie sind eure Meinungen und Erfahrungen zu dem Thema?
Weitere Short-Cuts aus Kommentar von Michal (gabru) entnommen (danke!):
STRG + Cursor Down / Up (Scrollen ohne Cursor zu verschieben)
STRG + Y (Zeile löschen)
ALT + Cursor Down / Up (Zeile nach Oben / Unten verschieben)
STRG + Cursor Links / Rechts (Wörterweise springen)
ALT + PageDown (Zeile klonen)
Passt auch zum Thema: Short-Cuts für Visual Studio im Blog von Stefan Falz:
Änderungen / Korrekturen:
16.06.08 - Kommentar von Michal in den Post eingepflegt.
28.08.08 - Link zu Short-Cuts für Visual Studio von Stefan Falz eingetragen.
LAN-Scan, aber richtig schnell! Teil -2
13.06.2008 19:04:37
|
Klaus Bock
Im vorherigen Artikel habe ich das Grundgerüst und den Test der parallelen Verarbeitung beschrieben. Heute will ich den eigentlichen Scan des LAN-Segments zeigen.
Wie in einem früheren Beitrag bereits angesprochen verwenden die Methoden der TPL Delegaten, welche die eigentliche Aufgabe ausführen. Die Anforderungen an eine solche Methode sind also:
- Es wird kein Rückgabewert benötigt.
- Die jeweilige Hostadresse als Argument entgegen nehmen.
- Die jeweilige IP-Adresse in einen Hostnamen auflösen.
- Die Gewährleistung das jeder gesendete Ping an den sendenden Thread zurückgegeben wird.
- Das empfangene PingReply-Objekt auswerten.
- Das Ergebnis threadsicher an ein Objekt übergeben welches die Ergebnisse hält.
Da die Anforderungen nun dargelegt wurden, kann jetzt die Umsetzung in den Code beginnen. Zur Verwendung als Delegat einer TPL Methode, muss das Argument als Typ Object übergeben werden. Sollte dies vergessen werden, wird man vom Compiler sehr schnell daran erinnert. Um Punkt 4. umzusetzen muss der Zugriff auf die Betriebssystemthreads gewährleistet sein. Deshalb muss die Methode die entsprechende Sicherheitsberechtigung anfordern. Genau dafür ist das SecurityPermissionAttribute vorgesehen. Also muss die Signatur wie folgt aussehen:
[SecurityPermission(SecurityAction.Demand,
Flags = SecurityPermissionFlag.ControlThread)]
private static void CheckHost(object hostNumber)
{
// hier der Code
}
Zur Gewährleistung von Punkt 4. habe ich die gesamte Logik zwischen die Methoden Thread.BeginThreadAffinity und Thread.EndThreadAffinity eingeschlossen. Zur Auflösung der IP-Adresse in einen Hostnamen, stellt das .NET-Framework die Dns-Klasse zur Verfügung. Um jedoch die Methoden der Klasse nutzen zu können, muss zunächst die als Zeichenfolge vorliegende IP-Adresse in ein IPAddress-Objekt konvertiert werden.
// IPAdress-Objekt erzeugen
IPAddress ipAdress = IPAddress.Parse(netSegment + hostNumber.ToString());
// den HostName der IP-Adresse ermitteln
string hostName = Dns.GetHostEntry(ipAdress).HostName;
Falls die IP-Adresse nicht aufgelöst werden kann, gibt die Eigenschaft HostName der Dns-Klasse die IP-Adresse wieder zurück. Da mir dieses Verhalten nicht gefällt, überprüfe ich ob es sich bei der zurückgegebenen Zeichenfolge um eine IP-Adresse handelt. Mit der Regex-Klasse ist dies einfach zu bewerkstelligen.
private const string ipPattern = @"((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)";
public static bool ValidateIP(string ipAddress)
{
if (Regex.IsMatch(ipAddress, ipPattern, RegexOptions.CultureInvariant))
{
return true;
}
return false;
}
Da die Verwendung der Anwendung nur in einem LAN Vorgesehen ist, können die PingOptions mit entsprechend niedrigen Werten konfiguriert werden. In einem LAN kommen eher selten mehr als zwei Weiterleitungen vor. Der Standard-Timeout der Ping-Klasse von 5 Sekunden ist für eine Verwendung in einem LAN wohl auch etwas zu hoch angesetzt.
Zum auswerten des Status des PingReply-Objekts reicht es im allgemeinen auf die Zustände Success, DestinationHostUnreachable und TimedOut der IPStatus Enumeration zu prüfen.
Um die einzelnen Ergebnisse threadsicher an das Objekt zu übergeben welches die Ergebnisse speichert, muss dieses Objekt einen Mechanismus zur Threadsicherheit bereitstellen. Dieses Objekt, in meinem Fall die Klasse ClientList auf die ich später noch eingehe werde, bietet die Eigenschaft AddedSuccessfull welche signalisiert, dass das Ergebnis erfolgreich gespeichert wurde. In dieser Klasse wird ein Mutex verwendet, der den Zugriff der Thread's regelt. Die genannte Eigenschaft, vom Typ bool, wird verwendet um zu überwachen wann das Sichern eines Ergebnis erfolgreich war.
// den ReplyStatus auswerten
switch (reply.Status)
{
// Ping erfolgreich
case IPStatus.Success:
while (true)
{
clientList.AddOrReplace(ipAdress.ToString(), hostName, true);
if (clientList.AddedSuccessfull)
{
break;
}
Thread.Sleep(10);
}
break;
// weitere Code
}
Sollte der Zugriff zum Speichern durch einen anderen Thread kurzzeitig verhindert werden, wird nach einer kurzen Pause erneut versucht zu Sichern. Auf diese Weiße kann gewährleistet werden, dass die Ergebnisse tatsächlich so geschrieben werden wie sie vorliegen und nicht von einem zweiten Thread mit einem anderen Ergebnis überschrieben werden.
Der Vollständigkeit halber hier noch die komplette Methode:
[SecurityPermission(SecurityAction.Demand,
Flags = SecurityPermissionFlag.ControlThread)]
private static void CheckHost(object hostNumber)
{
// Pingprüfung an den physischen Betriebssystem-Thread binden
Thread.BeginThreadAffinity();
// neuen Ping initialisieren
Ping pingSender = new Ping();
// Ping-Optionen festlegen
PingOptions options = new PingOptions(2, true);
PingReply reply;
int timeOut = 60;
byte[] buffer = new byte[32];
// IPAdress-Objekt erzeugen
IPAddress ipAdress = IPAddress.Parse(netSegment + hostNumber.ToString());
// den HostName der IP-Adresse ermitteln
string hostName = Dns.GetHostEntry(ipAdress).HostName;
// prüfe ob die IP-Adresse als HostName zurückgegeben wird.
if (IPHelper.ValidateIP(hostName))
{
// HostName als unbekannt kennzeichnen
hostName = "Unbekannt";
// Ping senden und Antwort an das reply-Objekt übergeben
reply = pingSender.Send(ipAdress, timeOut, buffer, options);
// wenn Ping erfolgreich, IP-Adresse mit HostName unbekannt eintragen.
if (reply.Status == IPStatus.Success)
{
while (true)
{
clientList.AddOrReplace(ipAdress.ToString(), hostName, true);
if (clientList.AddedSuccessfull)
{
break;
}
Thread.Sleep(10);
}
}
}
else
{
// Ping senden und Antwort an das reply-Objekt übergeben
reply = pingSender.Send(hostName, timeOut, buffer, options);
// den ReplyStatus auswerten
switch (reply.Status)
{
// Ping erfolgreich
case IPStatus.Success:
while (true)
{
clientList.AddOrReplace(ipAdress.ToString(), hostName, true);
if (clientList.AddedSuccessfull)
{
break;
}
Thread.Sleep(10);
}
break;
// Host nicht erreichbar
case IPStatus.DestinationHostUnreachable:
while (true)
{
clientList.AddOrReplace(ipAdress.ToString(), hostName, false);
if (clientList.AddedSuccessfull)
{
break;
}
Thread.Sleep(10);
}
break;
// Zeit abgelaufen
case IPStatus.TimedOut:
while (true)
{
clientList.AddOrReplace(ipAdress.ToString(), hostName, false);
if (clientList.AddedSuccessfull)
{
break;
}
Thread.Sleep(10);
}
break;
}
}
// Thread-Bindung aufheben
Thread.EndThreadAffinity();
}
Die Klasse ClientList, welche die Ergebnisse zur weiteren Verwendung speichert, werde ich im dritten und letzten Teil vorstellen.
MbUnit 2.4 PlugIn for ReSharper 4.0 Final
13.06.2008 15:12:50
|
Albert Weinert
Update (20.06):
Beta 9 is ready ReSharper-MbUnit-Beta9.zip it fixes Issues 11, 17, 18 and some other things. Go and get it and please provide feedback. If work stable it will be included in the next MbUnit 2.4 Update.
Know Issues: DependsOn() and DataFixture() not supported in R# (not fixable yet)
A new Version of the PlugIn to Run MbUnit 2.4 Test in ReSharper is available.
You can download it: ReSharper-MbUnit-Beta8.zip
There is also an Update for ReSharper 3.1 which fixes some bugs..
Know-Issues:
The results of an RowTest with Enums are not displayed in the Unit Test Explorer.
Have fun.

Debugging BLog
13.06.2008 07:07:09
|
Boas Enkler
Events für User- und CustomControls definieren und benutzen
12.06.2008 21:44:00
|
Peter Bucher
In der Welt von ASP.NET gibt es - im Gegensatz zu Classic ASP - ein Eventsystem das in der ASP.NET Engine verwurzelt ist.
Dazugehörend haben viele ASP.NET Controls Events. Das bekannteste ist wohl Button.Click, über diesen Event kann festgestellt werden ob ein bestimmter Button gedrückt wurde, oder nicht.
Nun gibt es ja die Möglichkeit eigene User- und CustomControls zu schreiben.
Diese können mit Events ausgestattet werden, und genau um das geht es hier in diesem Artikel.
Wie funktionieren die Events in ASP.NET?
Grundsätzlich ereignen sich alle Aktionen auf dem Client, bspw. klickt eine Person an einem Computer in dessen Webbrowser auf einen Button.
Danach wird das Formular abgesendet und der Server empfängt dieses.
Der Server leitet den Http-Request (Die Http-Anfrage) an die ASP.NET Engine weiter.
Die Engine findet dann anhand der <Control>.UniqueID (Siehe: Identifizierung von Controls: Control.ID / .ClientID / .UniqueID) das Control zu dem die jeweiligen Daten gehören.
Wenn dieses Control gefunden wurde, leitet die Engine die gesamten POST-Daten (Formulardaten) an das bestreffende Control weiter.
Sind die Daten geändert worden, bzw. befinden sich die Daten in einem erwarteten Zustand, löst das Control den Event aus, ansonsten nicht.
Dies ist die normale Vorgehensweise von Events (Die Page Events laufen ähnlich ab), die über POST (Formular, Postback) ausgelöst werden.
Wie definiere ich einen Event, oder was ist ein Event überhaupt?
Für die Grundlagen zur Event-Erstellung, mit oder ohne nutzerspezifische Argumente, verweise ich hier auf den FAQ Thread des C#-Forums myCSHarp.de.
Die FAQ von myCSharp.de als solches ist auch für andere Sprachspezifische Angelegenheit sehr zu empfehlen.
Wie / Wann werden die Events ausgelöst und gibt es mehrere Auslösearten?
Das trickreiche an Events in ASP.NET ist nicht die Dekleration der Events, sondern der Zeitpunkt an dem sie ausgelöst werden sollen.
Es gibt tatsächlich mehrere Arten von Zustandsveränderungen bei denen ein Event ausgelöst werden kann.
Folgend die Möglichkeiten von Zustandsänderungen durch einen Benutzer der Web Applikation ausgelöst:
- Werte die durch einen (oder mehrere) GET-Parameter (QueryString) empfangen werden, bspw. wenn der Benutzer auf einen Link klickt
- Werte die durch einen (oder mehrere) POST-Parameter (Form) empfangen werden, bspw. wenn der Benutzer Formularfelder ausgefüllt hat und dann auf einen Button klickt, oder aber nur auf einen Button klickt
Zudem gibt es noch weitere Faktoren und Möglichkeiten, die als Indikatoren für eine Eventauslösung benutzt werden können:
- Werte die durch einen (oder mehrere) POST-Parameter empfangen werden, die durch die __doPostback-Javascriptfunktion abgeschickt werden
- Zustandsänderungen aller Art auf der Serverseite (Datei, Datenbank, Session, Zeit, Datum, etc...
- Festgelegte Logik im Code, bspw. Vergleiche, etc...
Aller Anfang ist schwer leicht
Zuerst folgt ein Beispiel das auf einen GET-Parameter reagiert und bei Vorhandensein des Parameters einen Event auslöst.
C#:
namespace pb.Web.UI.WebControls.Examples
{
public class TestControlGetSimple : WebControl
{
public event EventHandler ParameterAvailable;
protected virtual void OnParameterAvailable(object sender, EventArgs e) {
if (this.ParameterAvailable != null)
this.ParameterAvailable(sender, e);
}
protected override HtmlTextWriterTag TagKey {
get {
return HtmlTextWriterTag.Div;
}
}
protected override void OnInit(EventArgs e) {
base.OnInit(e);
HyperLink link = new HyperLink();
link.ID = "hlTest";
link.Text = "Testlink";
link.NavigateUrl = "?test=1234";
this.Controls.Add(link);
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
string name = this.Context.Request.QueryString["test"];
if(!string.IsNullOrEmpty(name)) {
this.OnParameterAvailable(this, EventArgs.Empty);
}
}
}
}
Was genau passiert da jetzt?
Das Beispiel ist einfach aufgebaut. Zuerst wird ein Event mit einem Standard-Eventhandler (in .NET verfügbar) implementiert.
Danach wird die eventauslösende OnEvent-Methode definiert, die aufgerufen wird, wenn der Event ausgelöst werden soll.
Anschliessend wird per überschriebenen TagKey-Eigenschaft angegeben, dass das Control ein umschliessenden Div-Tag besitzen soll. (Im Beispielprojekt wird das für die Formatierung benutzt).
In der OnInit-Methode wird ein Objekt vom Typ Hyperlink angelegt, ein Text und eine Url + GET-Parameter angegeben und anschliessend zum Control hinzugefügt.
Jetzt kommt der spannende Teil: Das Event wird ausgelöst.
Beim Laden des Controls wird ein evt. vorhandener Parameter über <HttpContext>.Request.QueryString(<Key>) abgerufen, und anschliessend überprüft ob dieser null oder ein Leerstring (String.Empty) ist.
Falls dies nicht der Fall ist, wird der Event ausgelöst. Das war schon der ganze "Zauber" auf der Control-Seite.
Die Benutzung des Controls in einer ASP.NET Seite ist sehr einfach und geht so von der Hand, wie ansonsten ein Klick-Event eines Buttons abonniert wird.
Wie das Control registiert wird, um auf der Seite zu benutzen, kann im folgendenen Blogpost nachgelesen werden:
Beispiel:
ASPX:
<fieldset>
<legend>GET Beispiel (simple)</legend>
<pb:TestControlGetSimple ID="testGetSimple" runat="server" />
<br />
<asp:Label ID="lblInfoGetSimple" Text="Parameter nicht verfügbar" runat="server" />
</fieldset>
Codebehind (C#):
protected void Page_Load(object sender, EventArgs e) {
this.testGetSimple.ParameterAvailable += testGetSimple_ParameterAvailable;
}
void testGetSimple_ParameterAvailable(object sender, EventArgs e) {
this.lblInfoGetSimple.Text = "Parameter ist <strong>vorhanden</strong>";
}
Zuerst werden auf der ASP.NET Seite das Test-Control und ein Label hinzugefügt.
Anschliessend abonnieren wir das Event im Page_Load Eventhandler und fügen dem zugewiesenen Handler Code hinzu, damit das Label anzeigt, ob der Event ausgelöst wurde oder nicht.
Wenn der Link angeklickt wird und infolgedessen ein GET-Parameter vorhanden ist, wird das Event ausgelöst und im Eventhandler den Text des Labels geändert.
Aus Benutzersicht ist nur der geänderte Text sichtbar.
Das Beispiel wurde mit Absicht sehr simpel gehalten, um einen einfach Einstieg zu ermöglichen.
Ein erweitertes Beispiel mit GET-Parametern
Folgend der Code eines erweiterten Beispiels, das mithilfe einer Session erkennen kann, ob der aktuelle Wert des GET-Parametes geändert wurde. Den ASPX-Teil wird nicht mehr gezeigt, da er praktisch identisch zum Beispiel (Siehe Code) ist.
C#:
namespace pb.Web.UI.WebControls.Examples
{
public class TestControlGet : WebControl, INamingContainer
{
public delegate void NameChangedDelegate(object sender, NameChangedEventArgs e);
public event NameChangedDelegate NameChanged;
protected virtual void OnNameChanged(object sender, NameChangedEventArgs e) {
if (this.NameChanged != null)
this.NameChanged(sender, e);
}
protected override HtmlTextWriterTag TagKey {
get {
return HtmlTextWriterTag.Div;
}
}
protected override void OnInit(EventArgs e) {
base.OnInit(e);
for (int i = 0; i < 5; i++) {
HyperLink link = new HyperLink();
link.ID = "testLink" + i.ToString();
link.Text = "Patrick " + i.ToString();
link.NavigateUrl = "?name=Patrick" + i.ToString();
this.Controls.Add(link);
this.Controls.Add(new LiteralControl("<br />"));
}
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
string name = this.Context.Request.QueryString["name"];
string nameBefore;
object sessionValue = this.Context.Session["name"];
if (sessionValue != null)
nameBefore = sessionValue.ToString();
bool flag = false;
// Erste Änderung (ohne Session, erster Aufruf)
if (name != null && sessionValue == null)
flag = true;
// Änderung mithilfe der Session herausfinden
if (sessionValue != null && name != null && !sessionValue.Equals(name))
flag = true;
if(flag)
this.OnNameChanged(this, new NameChangedEventArgs(name));
this.Context.Session["name"] = name;
}
}
public class NameChangedEventArgs : EventArgs {
private string _newName;
public NameChangedEventArgs(string newName) {
this._newName = newName;
}
public string NewName {
get { return this._newName; }
}
}
}
In diesem Beispiel wird eine Liste von Links mit GET-Parametern ausgegeben.
Wenn der empfangene Parameter ändert, wird der Event ausgelöst.
Beim ersten Empfangen eines Wertes wird dieser in die Session geschrieben und dieser Spezialfall berücksichtigt.
Wird jedoch ein Wert empfangen, wenn die Session schon ein Wert enthält, wird auf Ungleichheit geprüft, falls wahr wird der Event ausgelöst.
Zudem wird in diesem Beispiel ein eigener Delegate benutzt, um eigene EventArgs zu unterstützen.
Im Eventhandler kann der geänderte Namen einfach über e.NewName abgerufen werden.
(Der Einfachheit halber habe ich keinen generischen EventHandler benutzt, obwohl dieser ab .NET 2.0 natürlich zu empfehlen wäre. Wie es geht, siehe: Eigenen Event definieren / Information zu Events (Externer Link: myCSharp.de) )
Einen Event über POST-Werte mithilfe von IPostBackEventHandler und ClientScript.GetPostBackEventReference auslösen
Wie weiter oben schon angesprochen, stellt ASP.NET selber eine Architektur bereit, um mit POST-Daten Events über eine spezielle Infrastruktur auszulösen.
Die jetzt vorgestellte Lösung basiert auf der __doPostBack-Funktion, die ASP.NET im Normalfall in jeder ASP.NET Seite zur Verfügung stellt.
Folgend die Definition der Schnittstelle.
C#:
public interface IPostBackEventHandler
{
void RaisePostBackEvent(string eventArgument);
}
Im Normalfall geschieht ein Postback über einen Html-Button, der das Formular absendet.
Das Formular kann aber auch per Javascript abgesendet werden, genau das nutzt die __doPostBack-Funktion.
Sie kann zusätzlich Parameter entgegennehmen und diese über HiddenFields (Versteckte Eingabefelder) zum Server schicken.
So ist nicht nur ein Abschicken und Prüfen von Form-Elementen möglich, sondern auch das übergeben beliebiger Elemente und zudem auch den Namen des Controls, von dem die Elemente bzw. Argumente kommen.
Über die Methode GetPostBackEventReference() der Klasse ClientScript finden sich viele Überladungen, die benutzt werden können um eine Javascript Postback-Referenz zu bekommen.
Dies ist nichts weiter als ein benutzerdefinierter Aufruf der __doPostBack-Funktion, mit eigenen Parametern.
ASP.NET stellt eine Schnittstelle Namens IPostBackEventHandler zur Verfügung, die implementiert werden kann, um über Postbacks mit der Möglichkeit der Übergabe von Elementen zu kommunizieren.
Dabei muss immer das Control selber (schlussendlich die UniqueID des Controls) übergeben werden, sowie Argumente nach Wunsch.
Vielleicht kennt der eine oder andere die __doostBack-Funktion aus dem GridView, wenn eine Zeile selektiert wird.
Dies wird genau nach diesem Schema erledigt.
Folgend nun das Beispiel (Wiederum nur das Control an sich, da der Rest praktisch gleich ist):
C#:
namespace pb.Web.UI.WebControls.Examples
{
public class TestControlPost : WebControl, INamingContainer, IPostBackEventHandler
{
public delegate void NameSelectedDelegate(object sender, NameSelectedEventArgs e);
public event NameSelectedDelegate NameSelected;
protected virtual void OnNameChanged(object sender, NameSelectedEventArgs e) {
if (this.NameSelected != null)
this.NameSelected(sender, e);
}
protected override HtmlTextWriterTag TagKey {
get {
return HtmlTextWriterTag.Div;
}
}
protected override void OnInit(EventArgs e) {
base.OnInit(e);
for (int i = 0; i < 5; i++) {
HyperLink link = new HyperLink();
link.ID = "testLink" + i.ToString();
link.Text = "Patrick" + i.ToString();
link.NavigateUrl = "#";
link.Attributes.Add("onclick", this.Page.ClientScript.GetPostBackEventReference(this, "Patrick " + i.ToString()));
this.Controls.Add(link);
this.Controls.Add(new LiteralControl("<br />"));
}
}
#region IPostBackEventHandler Members
public void RaisePostBackEvent(string eventArgument) {
if(this.NameSelected != null)
this.NameSelected(this, new NameSelectedEventArgs(eventArgument));
}
#endregion
}
public class NameSelectedEventArgs : EventArgs
{
private string _selectedName;
public NameSelectedEventArgs(string newName) {
this._selectedName = newName;
}
public string SelectedName {
get {
return this._selectedName;
}
}
}
}
Das Beispiel ist dem letzten Beispiel sehr ähnlich, jedoch geht es hier um das Selektieren eines Namens, nicht um die Änderung dessen.
Es werden auch HyperLinks erzeugt, und in dessen clientseitigem onclick-Eventhandler jeweils die PostBackEvent-Referenz mithilfe obengenannter Methode ein parameterisierter Javascript-Aufruf für das jeweilige Link erzeugt.
Dabei wird eine Referenz auf das Control selbst mitgegeben, damit ASP.NET das Control anhand der UniqueID identifizieren kann, und den Namen, der selektiert werden kann.
Die ASP.NET Engine merkt beim Durchgehen aller Controls, dass dieses Control die IPostBackEventHandler Schnittstelle implementiert und feuert dann ggf. bei Bestehen eines Events dass durch das Link gesendet wurde, das Event.
Dies geschieht dadurch, dass ASP.NET die Methode RaisePostBackEvent aufruft und ihr das Argument übergibt, dass vom Client gesendet wurde.
Aufgrund dieser Infos kann schlussendlich im Eventhandler auf das Argument zugegriffen werden.
Das Interface IPostBackDataHandler, Sinn und Nutzen
ASP.NET stellt noch ein weiteres Interface zur Verfügung, um Events auszulösen.
Dieses setzt zwei Methoden voraus, folgend die Definition:
C#:
public interface IPostBackDataHandler
{
bool LoadPostData(string postDataKey, NameValueCollection postCollection);
void RaisePostDataChangedEvent();
}
Im Beispiel auf der Seite von Microsoft, ist ein ziemlich sinnloses Beispiel zu finden, indem von einem WebControl ein Button nachgebaut wird.
Diese Schnittstelle wird nur existieren, damit Microsoft alle Form-Controls implementieren konnte.
In LoadPostData werden die UniqueID des Controls selber und die komplette Post-Collection angeboten.
Durch <Collection>[postDataKey] kann der Wert des Controls sehr einfach gelesen werden, der Rückgabetyp ist ein bool und bei einer Rückgabe von true wird die RaisePostDataChangedEvent()-Methode aufgerufen und der oder die Events können gefeuert werden.
ASP.NET ruft - auch durch die Interface-Markierung - jeweils die Methode LoadPostData automatisch auf.
Dies jedoch nur, wenn als TagKey bzw TagName des Controls ein bekanntes Form-Control gesetzt ist (Was auch Sinn macht).
Wenn die Methode bei einem eigenen Control trotzdem aufgerufen werden soll, so muss die Methode RegisterRequiresPostBack (Siehe auch: Understanding what Page.RegisterRequiresPostBack does) von der Klasse Page aufgerufen werden und das zu registrierende Control übergeben werden.
Für eine Implementation der Controls: Button, DropDownList, TextBox, etc... ein sehr sinnvolles Interface.
Bei der Implementation eines eigenen Controls, das kein Form-Tag darstellt geht es m.E. einfacher und besser ohne dieses Interface.
Siehe auch:
An dieser Stelle gibt es kein Beispiel, jedoch ist im Download auch ein solches Beispiel vorhanden, dass das Interface benutzt.
Inhalt des Downloads:
- Alle hier darstellten Beispiele
- IPostBackDataHandler-Beispiel
- Alles in einer Solution mit einem Control-Library Projekt und einem Web Application Project zum Testen
Download:
Dank geht an:
Norbert Eder für das Review des Artikels
Ich freue mich über jegliche Kommentare!
Design von barrierefreien ASP.NET-Websites
12.06.2008 14:40:30
|
Jürgen Gutsch
Vorhin hat mich Peter Bucher darauf aufmerksam gemacht, das dieses Blog beim googeln nach "asp.net barrierefreiheit" an erster Stelle steht. Tolle Sache :-)
Dabei ist mir eine ältere, aber nicht weniger interessante Ressource aus der MSDN an dritter Stelle des Suchergebnisses aufgefallen:
Design von barrierefreien ASP.NET-Websites (Original von Scott Mitchell)
"Nutzen Sie die Vorteile der Vererbung im .NET Framework und erweitern Sie ASP.NET-Klassen so, dass der generierte ASP.NET-Code für Benutzer mit Behinderungen vollständig zugänglich ist."
http://msdn.microsoft.com/de-de/library/bb978918.aspx
Wenngleich auch die Code-Beispiele schon etwas älter sind, die enthaltenen Infos über barrierefreie Webentwicklung allgemein und WAI, WCAG und Section 508 sind auf alle Fälle interessant.
Design von barrierefreien ASP.NET-Websites
12.06.2008 14:40:30
|
Jürgen Gutsch
Vorhin hat mich Peter Bucher darauf aufmerksam gemacht, das dieses Blog beim googeln nach "asp.net barrierefreiheit" an erster Stelle steht. Tolle Sache :-)
Dabei ist mir eine ältere, aber nicht weniger interessante Ressource aus der MSDN an dritter Stelle des Suchergebnisses aufgefallen:
Design von barrierefreien ASP.NET-Websites (Original von Scott Mitchell)
"Nutzen Sie die Vorteile der Vererbung im .NET Framework und erweitern Sie ASP.NET-Klassen so, dass der generierte ASP.NET-Code für Benutzer mit Behinderungen vollständig zugänglich ist."
http://msdn.microsoft.com/de-de/library/bb978918.aspx
Wenngleich auch die Code-Beispiele schon etwas älter sind, die enthaltenen Infos über barrierefreie Webentwicklung allgemein und WAI, WCAG und Section 508 sind auf alle Fälle interessant.

Dunkles Visual Studio 2008 mit ReSharper 4
12.06.2008 14:23:13
|
Albert Weinert
Ich selbst benutze schon seit längeren auch einen "dunkles" Visual Studio, ich habe mir damals irgendeine Dark-Theme genommen und über die Zeit an meine Bedürfnisse angepasst. Dazu gehört unter anderem auch die Verwendung einer Schriftart für den Text-Editor die nicht über eine feste Laufweite verfügt Verdana. Darauf hat mich vor einiger Zeit Roland Weigelt drauf gebracht. Zusätzlich wird noch Segio UI für den Rest verwendet.
Proportional und Schwarz
Visual Studio arbeitet damit ohne Probleme und man hat den angenehmen Nebeneffekt das man mehr Text in eine Zeile bekommt. Anfangs ein wenig ungewöhnlich, aber man gewöhnt sich schnell dran. Nur ASCII-Art ist nun ein wenig schwierig.

Verdana als proportionale Schriftart deshalb weil man dort das große i von kleinen l sehr gut unterscheiden kann.
Des weiteren werden bei mir die Operatoren auch noch fett dargestellt, hauptsächlich damit man das ! im Quelltext besser erkennen kann.
Dies noch in einer anderen Farbe und schon kann man den kleinen not-Operator sehr schön erkennen.
Feinarbeit
Was mir bei einigen Dunklen-Themes für Visual Studio aufgefallen ist dass dies nicht sehr ausgearbeitet sind. Dies fällt dann auf wenn man man damit arbeitet.
So ist das Bracket Highlighting oft nicht schön, oder das markieren von Text.
So etwas habe ich in "langer" Arbeit soweit korrigiert, sicher noch nicht alles.
Visual Studio Bug
Auch wird einem Visual Studio Bug entgegen gewirkt, der bei der umfangreichen Einfärbung die ReSharper vornimmt. Zwischendurch passiert es das die Hintergrund Farben plötzlich falsch sind, dies dadurch behoben dass die Hintergrund Farben explizit gesetzt werden und nicht auf "Default" gelassen worden sind.
ReSharper 4
Die hier hinterlegte Einstellungen funktionieren nur gut mit dem ReSharper 4 und Visual Studio 2008. Dazu muss in den ReSharper-Options noch das erweiterte Einfärben aktiviert werden.
Beachtenswertes
Installiert man ein Update des ReSharpers dann muss die Farbpalette erneut importiert werden, sonst werden die Farben nicht richtig gesetzt, ob nun Visual Studio oder ReSharper die "Schuld" daran hat ist nicht wirklich geklärt.
Damit dies auch immer schnell und Einfach funktioniert, sind in den gespeicherten Einstellungen auch nur Fonts & Colors hinterlegt. So das keine anderen Einstellungen überschrieben werden.
Auch die HTML und XML Darstellung ist entsprechend angepasst. Somit das ein vernünftiges arbeiten damit möglich ist. Jedoch empfehle ich es an die eigenen Bedürfnisse anzupassen.
Bestes Dark-Theme?
Das ist natürlich subjektiv ;) Ich bin an weiteren Verbesserungen interessiert, und ich habe sicherlich immer noch nicht alles beachtet um es 100% Rund zu bekommen. Wenn jemand also Anpassungen daran vornimmt bin ich daran interessiert diese zu sehen und selbst zu nutzen. Somit immer raus mit der Sprache.
Download
Wenn jemand anderes die Einstellungen nutzen möchte, dann einfach die Settings-Datei hier herunterladen und in Visual Studio importieren. Fertig.
DarkResharperColors.zip

New blogroll member: Stefan Lieser
12.06.2008 12:39:27
|
Andre Loker
Have a look at Stefan's blog. He's into TDD, DDD, ASP.NET MVC, improving code quality and other Good Things™, so it's definitively worth reading. Most posts are in German, though. He's developing a ReSharper plugin for NHibernate, be sure to have a look at it!
Web Accessibility Checklist
12.06.2008 08:35:37
|
Jürgen Gutsch
Web Accessibility Checklist
12.06.2008 08:35:37
|
Jürgen Gutsch
HowTo: TFS Best Practice - Wie lege ich ein Projekt an?
11.06.2008 23:38:54
|
Robert Mühsig
Der TFS ist mit seinen ganzen tollen Funktionen sehr vielseitig, allerdings sollte man bereits am Anfang auf eine Sache achten: Wie strukturiere ich das Projekt?
Damit sind keine “logischen” Strukturen gemeint, sondern wie lager ich die Dateien richtig im TFS? Gibt es einen Leitfaden?
Die gute Nachricht: Ja - den TFS Guide!
Hinweis: Im Rahmen des ReadYou-Projektes werde ich den Source Code bei Codeplex (welche auf den TFS einsetzt) versuchen nach diesen Best-Practices unterzubringen.
Da dies allerdings (jedenfalls bei mir) immer mal wieder Kopfzerbrechen bereitet, ein kleines HowTo:
Warum das ganze eigentlich?
Auf der Codeplex Seite des TFS Guides findet man viele Tipps, warum man dies so oder so machen sollte - ein deutlichste Bild nehm ich direkt mal aus den Guide (Seite 50):
Erklärung:
Es gibt in der Entwicklung immer einen “Main” Pfad - an diesem Pfad wird ständig gearbeitet. Irgendwann wird ein “Release 1” herausgegeben.
Jetzt beginnt die Phase, in der sicherlich im “Release 1” Bugs auftreten und Fixes etc. nachgeliefert werden müssen. Natürlich muss unser Hauptentwicklungsteam die Software während dieser Zeit im “Main” Pfad weiterentwickeln können.
Jetzt könnte es aber passieren, dass im “Release 1” ein Fehler auftritt der unbedingt gefixt werden muss - allerdings ist die Entwicklung zum “Release 2” schon sehr weit fortgeschritten. Komplette Codeteile sind neu geschrieben wurden! Ein “Patch” ist daher jetzt nicht machbar.
Das sowas nicht passiert macht man “Branches” (dt.: Zweige) und “merged” (dt.: wieder vereinen) die am Ende wieder (wenn es nötig ist) in den Entwicklungszweig.
Das mal als kurze Erklärung - das PDF gibt noch mehr Hinweise, warum und wieso man sowas machen sollte.
Schritt 1: Workspace anlegen
Als erstes muss auf unser Entwicklungsmaschine ein Workspace zum TFS Projekt her - daher gehen wir auf den Team Explorer -> Soure Control (kann hier runtergeladen werden) und klicken einfach beim Projekt auf “Get Latest Version“:

Dort wählt man einen Speicherort aus - nachdem das gemacht wurde, sollte sowas zu sehen sein:
Falls man feststellt, dass das Verzeichnis nicht das richtige war, muss man das Mapping im Workspace-Setting umstellen. Um hier rein zu kommen einfach mal hier klicken:
Schritt 2: Ordnerstruktur über den Team Explorer / Source Control anlegen
In diesem Schritt legen wir jetzt unsere Ordnerstruktur an - das wird genauso auch auf der Clientseite im Workspace übertragen.
Am Ende sollte man sowas haben - ein leeres Grundgerüst:
Schritt 3: Leere Solution anlegen
Jetzt legen wir uns eine leere Solution an, dabei muss die Location auf “[Workspace-Ordner]\Main\Source” stehen!
Nachdem das gemacht wurde, sieht man das Solution-File auch bereits im TFS in der Source Control Ansicht:
Schritt 4: Projekte anlegen
Die Projekte liegen nicht direkt mit dort, wo die Solution liegt, sondern in einem extra Source Ordner (im TFS Guide steht dazu, warum und wieso
), daher habe ich einfach zwei Solution-Folder “Source” & “Tests” (für die UnitTest-Projekte) angelegt:
Wichtig ist hierbei auch, dass als Location auch der “\Source” Unterordner angegeben ist - ansonsten wird es falsch abgespeichert:
Tipp: Falls man was auf der Clientseite falsch gemacht hat, muss es auch auf dem TFS berichtigt werden - dazu gibt es einen unscheinbaren “Delete”-Knopf. In der Source Control Sicht den entsprechenden Ordner markieren & löschen und dann auf “Checkin pending changes” - jetzt ist er wieder weg
Schritt 5: Fertig
Wenn wir alles richtig gemacht haben, sieht es so aus:
Ich muss allerdings zugeben, dass die Solution-Folder nicht sein müssen, wichtig ist erstmal, dass es auf dem Server auch richtig hinterlegt ist:
Abschließender Hinweis:
Das ist natürlich nur so einfach bei einem neuen Projekt - alte Projekte in diese Struktur packen ist sicherlich nicht ganz so leicht, aber auf der TFS Guide Seite findet man noch sehr viele Informationen darüber.
Falls irgendwas mit meinen Ratschlägen nicht stimmt, dann einfach Feedback geben
ShareThis
HowToCode "ReadYou": ToDo Liste managen
10.06.2008 22:56:56
|
Robert Mühsig
Gestern habe ich bei Codeplex ein “ReadYou” Projekt angelegt.
Info am Rande: Die “HowTos” sind allgemeiner gehalten - in der Kategorie “HowToCode” dreht es sich um zusammengesetze spezielle Sachen, wobei ich hier “HowTos” etc. verlinke - so ist jedenfalls momentan meine Vorstellung von diesen beiden Kategorien
Um einen Überblick über die verschiedenen Tätigkeiten bei “ReadYou” zu behalten muss unbedingt eine ToDo Liste her.
Info am Rande: Ich dokumentiere dies Schritt für Schritt - sodass ich dies evtl. später auch mal unseren Azubis vermachen kann, daher auch der “low-level” Einstieg
Ob das Feature auf Codeplex genau so genutzt wird, weiß ich natürlich nicht - da am Ende allerdings ein Team Foundation Server steckt und dort solche ToDos sich (mehr oder weniger komfortabel) als WorkItem wiedergeben lassen, werde ich dies hier auch machen
Codeplex: “Issue Tracker”
Mit dem Tracker kann man sehr leicht WorkItems/Issues/Features anlegen.
Man kann dazu viele Details mit hinzufügen:
Komponenten - Grobstruktur
Codeplex bietet nettes kleines Feld namens “Component”:
Hier können wir unsere Applikation erst mal grob strukturieren:
Genau diese Komponenten legen wir an:
Visual Studio 2008: Team Explorer Integration
Da ich natürlich nicht immer auf die Codeplex Seite die neuen ToDos anlegen möchte, geht dies auch mit dem Team Explorer. Hier sehen wir die selben Input-Felder wie auf der Website (diese Eingabemaske ist vom TFS Projekt Template abhängig) :
Visual Studio 2008: ToDos erstellen
Im ersten Schritt habe ich erstmal meine nächsten Schritte als WorkItem beschrieben:
Wie zu sehen ist, soll erstmal eine Ordnerstruktur her und wir widmen uns gleich zu beginn einem Kernelement: Das User System.
Was haben wir hier gelernt?
Überblick über ein Projekt zu behalten ist nicht ganz einfach - ein ToDo Zettel ist ganz nett, allerdings werden wir später noch herausfinden, was bei diesen WorkItems noch schick ist und warum es sich lohnt, so eine Art Kreislauf einzuhalten:
Schritt 1: Anforderung kommt rein
Ein Kunde (in dem Fall ich) möchte ein bestimmtes Features, z.B. sollen sich User anmelden können usw. (siehe hier).
Schritt 2: Bewerten / Aufwand abschätzen
Der Schritt ist etwas “schwammig” bei mir hier - normalerweise sollte der Entwickler an dieser stelle bereits eine ungefähre Ahnung haben, was da eigentlich gewollt ist und auch eine Ahnung haben, wie lange dies oder jenes dauert. Hier kann auch eine Konzeptionsphase sein (oder sogar sollte
)
Schritt 3: In entsprechende WorkItem umwandeln
Wenn das soweit ok geht (und vom Projektleiter abgesegnet wurde etc.) müssen wir die schwammigen Featurebeschreibungen in konkrete ToDos umwandeln.
Es kann auch sein, dass hier gar kein WorkItem abfällt, weil es z.B. kein Code zu schreiben gibt und auch sonst eher eine “administrative Aufgabe” ist.
Schritt 4: Implementieren
Da wir hier nach Test-Driven-Development vorgehen, wird während dieser Phase bereits ausgiebig getestet - jedenfalls wird hier alles eingebaut, was nötig ist um das zu erfüllen was gefordert ist.
Schritt 5: Testen
Hier sollte alles nochmal überprüft werden - nach dieser Phase geht es live!
Schritt 6: Ausliefern & WorkItem schließen
Wenn alles funktioniert, dass Feature fertig implementiert wurde und auch beim Kunden läuft, können wir hier das WorkItem schließen und können uns erstmal zurücklehnen
Da man mit den Unit-Tests in Zusammenhang mit WorkItems was schickes machen kann, wollte ich dies nochmal hervorheben.
Im nächsten Blogpost gibt es also das erste mal direkten Code zu sehen - jedenfalls werden wir das Visual Studio nicht nur zum Managen nehmen, sondern auch zu unserer eigentlichen Aufgabe zurückkehren: Coden!
ShareThis
.NET Blog - Refresh
10.06.2008 11:14:16
|
Norbert Eder
Mit zunehmender Zahl an Artikeln und Besuchern, musste die Online-Präsenz
http://www.dotnet-blog.com (englischsprachig) nun endlich ein Update erfahren:
Neues Layout
Zusätzlich wurden auch die
Kategorien angepasst. D.h. es wurde nicht nur die Anzahl verringert, sondern auch die Aussagekraft erhöht.
Digital Lifestyle im Auto
10.06.2008 10:07:00
|
Lori Grosland

Wie sieht das Digital Lifestyle im Auto aus? Letzte Woche habe ich mit Oliver Riekenbrauk darüber gesprochen. Er ist Marketing Manager für die Microsoft Automotive Business Group in Europa und hat mir ein Fiat Bravo gezeigt, das mit Fiats Blue&Me-System ausgerüstet ist. Blue&Me basierest auf einem Microsoft Technologie und ist ein leicht-zu-bedienendes Infotainment-System mit einem Bluetooth-System fürs Handy im Auto, ein USB-Port für den Anschluss eines MP3-Players und alles (Handy, MP3-Player und Navigationssystem) kann per Sprachbefehl gesteuert werden.
Auch ein Vorteil zu einem USB-Port im Auto, ist das das System kann einfach upgedatet werden. Jeden Tag gibt es neue Telefonen, PDAs und MP3-Playern und über diesen USB-Port kann Blue&Me nachträglich mit diesen Geräten upgegradet werden.
Blue&Me ist in Europa momentan nur in Fiat, Alfa Romeo, Lancia und IVECO-Modellen zu haben. In Nordamerika benutzt Ford das Microsoft Auto Softwareplattform in einem Produkt namens Sync. In die Zukunft wird es weitere Automarken mit so einem Infotainment-System geben.
In diesem Video Oliver zeigt mir wie benutzerfreundlich und unkompliziert das Blue&Me System ist.
Und wieder gibt es Bücher zu gewinnen...
10.06.2008 08:20:25
|
Jürgen Gutsch
HowTo: Codeplex Projekt anlegen
09.06.2008 23:33:26
|
Robert Mühsig
Für das Community-Projekt “ReadYou” habe ich nun ein Codeplex Projekt angelegt. Ich werde demnächst ein größeren ReadYou Post bringen - dies ist zur Vorbereitung
Das HowTo soll nur Anlaufinformationen zu dem ohnehin einfachen Registrierprozess darstellen (falls jemand anderes auch das Interesse hegt, bei Codeplex ein Projekt anzulegen) :
Nachdem wir angemeldet sind, können wir einfach auf der rechten Seite ein neues Projekt anlegen:
Die wichtigsten Daten angeben:
Den Codeplex User Agreements noch zustimmen:
Und da ist unser Projekt:
Nächster Schritt (bzw. hat man Zeit bis zum Releasen) :
Der Wahl einer Softwarelizenz. Es gibt bei Codeplex einige Open Source Lizenzen zur Auswahl, darunter die GPL, Apache Licence oder auch die MS-PL. Welche die richtige ist, ist momentan für mich auch ein Rätsel
Frist: 30 Tage bis zum Löschen!
Wie bereits oben in dem Screenshot zu sehen ist, gibt es beim Anlegen eine Deadline von 30 Tagen - in dieser Zeit muss das Projekt gepublished werden (ist das überhaupt ein Wort?
) - keiner mag leere Projekte, daher dieser Filter.
Wie verbinde ich mich nun mit dem Projekt?
Ich werde den TFS Team Explorer nehmen, es gibt allerdings noch andere Clients.
Interessant: Continuous Integration mit CruiseControl.NET ist es mit Codeplex möglich - siehe hier. Vielleicht ist das für später ganz interessant.
Die eigentlichen Verbindungsdetails lassen sich über den Reiter “Source Control” abrufen:
Das ganze tippen wir mal in unser Visual Studio über den Team Explorer ein:
Und siehe da - unser leeres Projekt:
Jetzt können wir anfangen Work Items/Source Code hochzuladen - wie genau und was da die Best Practices sind, versuche ich in ein paar HowTos bzw. einem größeren ReadYou Post zu veranschaulichen.
Weitere Informationen findet man auf der Codeplex Seite selbst.
ShareThis
Wöchentliche Rundablage: Silverlight 2, WPF, ASP.NET MVC, jQuery…
09.06.2008 21:08:53
|
Robert Mühsig
Silverlight 2:
WPF / Windows Presenation Foundation:
ASP.NET / ASP.NET MVC:
jQuery:
.NET Framework:
LINQ:
Tools:
TDD:
Pattern:
WCF:
CSS / Icons:
ShareThis
Web Test Recorder Toolbar wird unter Vista 64 nicht angezeigt
09.06.2008 20:57:40
|
Thomas Schissler
Zum Aufzeichnen von WebTests mit VSTS wird ein Web Test Recorder Toolbar im IE integriert.
Unter meinem Vista 64 Bit hatte ich allerdings das Problem, dass der Toolbar dort
partou nicht angezeigt wurde. Nach einigem Suchen habe ich dann die Lösung gefunden:
VSTS 2008 : Vista (64 bit) : Recorder bar does not appear when recording a new
webtest
Fix: Vista caches the list of explorer bars you have available and the recorder
bar was not included in your list. The fix is to force Windows to rebuild that
cache. To do this, first make sure you have all Internet Explorer instances
shut down, then open the 32 bit registry editor and delete the following keys:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component
Categories\{00021493-0000-0000-C000-000000000046}
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component
Categories\{00021494-0000-0000-C000-000000000046}
[Note: by default, the 32 bit registry editor is located in %WINDIR%\SysWow64\RegEdt32.exe]
The next time you boot Internet Explorer, your explorer bar cache will be rebuilt
and the recorder bar should be available.
Nachdem ich diese beiden Registry-Keys gelöscht habe, wurde der Toolbar angezeigt.
Weitere Infos und tipps bei Probleme mit dem Web Recoder Toolbar finden sich unter Michael
Taute's Blog : Diagnosing and fixing Web Test recorder bar issues.
Visual Studio 2008 Extensions for SharePoint
09.06.2008 12:45:49
|
Jens Häupel
Endlich kann auch mit Visual Studio 2008 Sharepoint Entwicklung betrieben werden. Die Erweiterungsbibliotheken und einiges mehr stehen zum Download bereit.
Visual Studio 2008 extensions for SharePoint
Provides project templates for SharePoint artifacts and F5 solution debugging on Visual Studio 2008.
Download
Visual Studio extensions for SharePoint User Guide
150 Pages of User Guide for the Visual Studio extensions for SharePoint including tool descriptions and step by step how to guide’s for each project template including workflow.
Download
A getting started with SharePoint flyer
One side is for IT Professionals and the other side is for developers.
Download
SharePoint Development for .NET Developers
A new landing page for SharePoint developers with lots of new content. Everything from videos and online MSDN Virtual Labs to sample PPTs and Demos for presentations.
And don’t forget the SharePoint Developer and Programming Forum is resourced so customers can get answers.
In eigener Sache: Diagramm-Tool mit EPS-Export gesucht
09.06.2008 08:40:43
|
Norbert Eder
Nach langer Suche und keinem zufriedenstellenden Ergebnis wende ich mich hiermit an meine Leser. Möglicherweise hat jemand einen Tipp für mich.
Gesucht: Ein Werkzeug um Fluss-Diagramme etc. zu erstellen, welche als EPS exportiert werden können.
Anforderungen:
- Diagramme sollten durchaus nett anzusehen sein. D.h. 80er Jahre Stil ist nicht unbedingt gefragt
- Preise á la Adobe-Produkte möchte ich definitiv nicht ausgeben, ich bin aber bereit den einen oder anderen Euro auszugeben
- Sollte unter Vista lauffähig sein
Für sachdienliche Hinweise wäre ich sehr dankbar. Bitte jedoch nur Hinweise auf Anwendungen, die getestet wurden.
dotnet-forum.de mit eigener Knowledge Base
09.06.2008 08:04:00
|
Jan Welker
Im dotnet-forum.de gibt es ab sofort eine eigene
Knowledge Base. Die Knowledge Base ist eine strukturierte Sammlung von Fachartikeln
aus den Bereichen .NET-Entwicklung, IT-Professional und Testberichten von Büchern
und Entwicklersoftware.
Die Knowledge Base bietet gegenüber dem Forum einige Vorteile:
1. Artikel können mit dem Windows Live Writer veröffentlicht werden
2. Artikel können kommentiert werden, diese Kommentare können vom Autor moderiert
werden
3. Artikel können von den Lesern bewertet werden
4. Die Kategorien der Knowledge Base können jederzeit flexibel angepasst werden
5. Es gibt RSS Feeds für jeden Autor und für jede Kategorie
Die Knowledge Base würde von Alex
Bierhaus und Jan-Cornelius
Molnar vom VB-Magazin.de entwickelt und
uns freundlicherweise zu Verfügung gestellt. Jan und Alex haben bei der Entwicklung
großen Wert darauf gelegt, die die neuen Sprachfeatures von VB 9.0 wie zum Beispiel
Linq einzusetzen um so eine performante und skalierbare Anwendung zu schaffen die
sich gut in den CommunityServer integrieren lässt.
Vielen Dank an Alex und Jan!
Zu erreichen ist die Knowledge Base unter diesem Link: http://dotnet-forum.de/KnowledgeBase/
Silverlight 2 Beta 2 & Expression Blend 2.5 June 2008 Preview released
08.06.2008 19:02:25
|
Robert Mühsig
LAN-Scan, aber richtig schnell! Teil - 1
08.06.2008 17:25:41
|
Klaus Bock
Im vorherigen Artikel (To parallel or not to parallel) habe ich eine Aufgabe gezeigt die sich, durch den intensiven Zugriff auf die Festplatte, nicht sonderlich gut zur Parallelisierung eignet. In diesem Artikel will ich eine Methode zeigen wie trotz intensiver E/A-Zugriffe, allerdings auf die Netzwerkkarte, sehr gut Parallelisiert werden kann. Gerade das "pingen" von ganzen LAN-Segmenten lässt sich gut Parallelisieren, da der Thread welcher den Ping ausführt solange wartet bis er Antwort erhält oder der Timeout abgelaufen ist. Während der Thread, oder Ping, auf Antwort wartet kann der nächste Ping schon wieder abgesetzt werden. Hier gilt es die ideale Anzahl von gleichzeitig initialisierten Ping-Objekten zu bestimmen. Während verschiedener Tests habe ich den Wert von 36 Thread's pro Kern als besten ermittelt. Für jene unter euch die's nicht glauben ist hier ein ScreenShot mit der Zeit:
Und als Nachweis dass die Threads auch wirklich etwas tun, außer Thread.Sleep(), hier ein ScreenShot mit dem Ergebnis:
Wie aus dem ScreenShot ersichtlich wird der Hostnamen aufgelöst und der Online-Status ermittelt. Ich finde ein ganzes LAN-Segment mit 254 möglichen Adressen in rund 2 Sekunden zu überprüfen und auszuwerten ist richtig schnell, oder etwa nicht?
Ich verwende dieses mal nicht die Parallel-Klasse, sondern die Task- und TaskManager-Klasse aus der TPL. Die TaskManager-Klasse bietet durch Verwendung einer TaskManagerPolicy die Möglichkeit, sehr genau das Verhalten der Thread-Erzeugung und -Verwendung zu steuern. In dieser Policy wird festgelegt:
- Die minimale Anzahl der CPU's die verwendet werden soll.
- Die maximale Anzahl der CPU's die verwendet werden soll.
- Die ideale Anzahl an Thread's pro CPU, die verwendet werden soll.
- Die maximale Größe des Stack.
- Die Priorität der verwendeten Thread's.
Klingt ja ganz nett. Doch ich wollte wissen, ob die Policy tatsächlich auch so umgesetzt wird. Also habe ich mir eine Methode geschrieben um das zu überprüfen. In dieser Methode wird die verwaltete ID des jeweiligen Thread ermittelt und in eine Hashtable eingefügt, wenn die ID noch nicht in dieser vorhanden ist. Hier der Code der Test-Methode:
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlThread)]
private static void SimulateCheck(object obj)
{
// ThreadAffinität wird verwendet um das gleiche Verhalten
// wie in der OriginalMethode zu simulieren
Thread.BeginThreadAffinity();
// die managed ThreadId holen
int tId = Thread.CurrentThread.ManagedThreadId;
// prüfen ob die ThreadID bereits in der Tabelle vorhanden ist.
if (!hashTable.ContainsKey(tId))
{
// nicht vorhanden, jetzt hinzufügen
hashTable.Add(tId, string.Empty);
}
// Pause, in etwa so lange wie die Ping-Verarbeitung
// in der OriginalMethode benötigt.
Thread.Sleep(600);
// ThreadAffinität beenden.
Thread.EndThreadAffinity();
}
Die TaskManagerPolicy soll also gewährleisten das bei einer Anzahl von 36 Thread's, als idealThreadCount, auf einem DualCore System nie mehr als 72 Thread's erzeugt und verwendet werden. In der Hauptmethode wird eine Liste von 253 Thread,s erzeugt und abgearbeitet. Anschließend wird diese Liste durchlaufen und jeder Thread auf seine Beendigung überprüft. Nachfolgend der verwendetet Code in der Hauptmethode:
static void Main(string[] args)
{
//ipHelper = new IPHelper(IPHelper.GetLocalIPAdress(false));
netSegment = "192.168.1."; // ipHelper.BaseAdress;
// ClientList initialisieren
clientList = new ClientList();
hashTable = new Hashtable();
// neue Stopwatch-Instanz initialisieren
Stopwatch sw = new Stopwatch();
#region using Tasks
// Initialisiert eine neue TaskManager-Instanz mit der Policy
// nutze min. 1 CPU,
// nutze max. alle CPU's,
// ideale Anzahl der Threads (ermittelt 36)
// maxStackSize Default,
// ThreadPriorität grösser als Normal
TaskManager manager = new TaskManager(
new TaskManagerPolicy(
1,
Environment.ProcessorCount,
threadCount,
0,
ThreadPriority.AboveNormal));
Console.WriteLine("starte parallele Überprüfung. Verwende PFX Tasks.");
sw.Start();
// generische Liste vom Typ Task
// mit 253 Elementen initialisieren
List<Task> taskList = new List<Task>(253);
// hostAdress mit 1 initialisieren
int hostAdress = 1;
// true, bis hostAdress 254 erreicht
for (int i = 0; hostAdress < 255; i++)
{
// eine neue Instanz der Task-Klasse mit TaskManager
task = Task.Create(
SimulateCheck,
hostAdress,
manager,
TaskCreationOptions.None);
// den Task zur Taskliste hinzufügen.
// der Task wird sofort gestartet
taskList.Add(task);
// hostAdress erhöhen
hostAdress++;
}
// durch die taskList iterieren um zu warten bis alle
// Tasks beendet sind.
foreach (Task task in taskList)
{
task.Wait();
// prüfen ob der Task beendet ist
if (task.IsCompleted)
{
// das Task-Objekt entsorgen
task.Dispose();
}
}
// TaskManager entsorgen
manager.Dispose();
// benötigte Zeit abfragen
elapsedTime = sw.Elapsed;
sw.Reset();
Console.WriteLine("Benötigte Zeit: " + elapsedTime.ToString());
Console.WriteLine();
#endregion
// StringBuilder wird verwendet um das Ergebnis in einer Reihe auszugeben
StringBuilder sb = new StringBuilder(hashTable.Count);
Console.WriteLine("Thread-Verwendung:");
Console.WriteLine(string.Format("Anzahl der Threads erwartet {0}",
threadCount * Environment.ProcessorCount));
Console.WriteLine("Anzahl der verwendeten Threads: " + hashTable.Count);
Console.WriteLine();
Console.WriteLine("Verwendete ThreadIDs:");
foreach (DictionaryEntry de in hashTable)
{
sb.Append(de.Key.ToString()).Append(", ");
}
// letztes Komma und Leerzeichen entfernen
Console.WriteLine(sb.ToString().Trim(',', ' '));
Console.WriteLine();
Console.WriteLine("Zum beenden eine Taste drücken.");
Console.ReadKey();
}
Der untere Bereich dient nur zur Ausgabe der Tests in der Konsole. Hier die Ausgabe der obigen Methode:
Tatsächlich wird, wie im obigen ScreenShot zu sehen, die TaskManagerPolicy umgesetzt und nur 72 Thread's werden verwendet obwohl 253 Task's erzeugt werden.
Tatsächlich ist das wirklich nützliche an diesem Verfahren, dass je nach Anwendungsfall die Anzahl der verwendetet Thread's gesteuert werden kann. In einer Windows-Anwendung kann die Anzahl hoch gesetzt werden, da die Anwendung mit Sicherheit im Vordergrund läuft und der Anwender auf das Ergebnis wartet. Soll die Lösung in einem Dienst Verwendung finden, kann sowohl die Anzahl als auch die Priorität der erzeugten Thread's dem entsprechend niedrig gewählt werden. Denkbar ist auch eine variable Größe der Thread-Anzahl und -Priorität, je nach momentaner Auslastung des Systems. Gerade in der Verwendung als Dienst könnte das eine sauber Lösung sein um die Ressourcen des Systems nicht über Gebühr zu belasten.
Soweit zum Grundgerüst und dem Test der parallelen Verarbeitung. Das nächste mal werde ich auf den eigentlichen LAN-Scan und das threadsichere einfügen bzw. ersetzen des Ping-Ergebnis in der ClientList-Klasse eingehen.
Artikel: Flexibel und einfach wie HTML
08.06.2008 15:36:52
|
Norbert Eder

In der Ausgabe 03/08 der Visual Studio One findet sich ein Artikel zum Thema WPF, geschrieben von meiner Wenigkeit:
Nicht nur für Softwareentwickler gibt es (zu Recht) Styleguides. Auch für Windows-Anwendungen stehen von Microsoft offizielle Richtlinien zur Verfügung. So war es schon für Windows XP, und so ist es auch für Windows Vista. In diesem Artikel erfahren Sie mehr über den Windows Vista Styleguide und erhalten Anregungen und Hinweise dazu, wie Sie Ihre WPF-Anwendungen daran ausrichten können.
Weitere Informationen auf der Homepage der
Visual Studio One.
WPF und MVC
08.06.2008 13:45:41
|
Norbert Eder
Anwendungen sollten nicht nur schön anzusehen sein, sondern auch das robust und korrekt tun, wofür sie geschaffen wurden. Damit dem so ist, muss sich der Entwickler/Architekt natürlich zu Beginn eines Projektes so einige Gedanken machen. Denn nur durch ein gutes Grundgerüst werden Anforderungen á la
Erweiterbarkeit,
Testbarkeit,
einfache Wartung usw. auch erfüllt.
Das
Model View Controller Pattern ist da so ein Ansatz. Mittlerweile Jahrzehnte am Buckel hatte sich dieses Pattern immer wieder bewährt (in seiner ursprünglichen Form oder in einer abgewandelten).
Wie nun die Windows Presentation Foundation mit dem Model View Controller Pattern zusammen arbeitet, zeigt der Artikel
MVC Pattern mit WPF verwenden, welchen ich gestern auf
.NET GUI veröffentlicht habe.
To parallel or not to parallel?
07.06.2008 13:40:59
|
Klaus Bock
Da neuere Computer kaum noch mit Prozessoren mit nur einem Kern bestückt werden, wird sich früher oder später ein jeder einmal Gedanken über die Parallelisierung seiner Anwendungen machen müssen. Die Parallel Extension to the .NET Framework 3.5, derzeit als zweite CTP vorliegend, bietet einen relativ einfachen Einstieg in die Parallelisierung von rechenintensiven Aufgaben. Interessierte können die Juni CTP hier herunter laden.
Wie überall gibt aus beim parallelisieren Aufgaben die gut und solche die weniger gut geeignet sind. Methoden die sehr E/A-intensive Aufgaben erledigen sollen, eignen sich eher nicht so gut zur Parallelisierung, da jeder Thread so lange blockiert wird, bis der Zugriff auf die jeweilige Ressource wieder frei gegeben ist. Gerade aus diesem Grund habe ich ein Beispiel gewählt das genau solch eine Aufgabe erledigen soll, um die Leistungsfähigkeit der TPL (Task Parallel Library) zu zeigen. In der gestellten Aufgabe gilt es alle vorhandenen Assemblies im GAC aufzulisten und die zugehörigen Installationsreferenzen zu ermitteln. Sowohl das Auflisten der Assemblies als auch das Ermitteln der Referenzen erfolgt mit Hilfe der Fusion-API. Um überhaupt eine Größe zu haben mit der ich vergleichen konnte, habe ich die einzige mir bekannte Anwendung verwendet welche auch die Fusion-API nutzt; die gacutil.exe aus dem SDK. Ich hoffe hier nicht gegen Punkt 2 der Eula, welcher Vergleichsstests regelt, des .NET Framework zu verstoßen. Zur Ermittlung der Referenz-Zeit habe ich gacutil.exe mit dem Argument -lr in einem Prozess gestartet und mit der Stopwatch-Klasse die benötigte Zeit ermittelt. hier der Code:
Process proc = new Process();
proc.StartInfo.FileName = @"C:\Programme\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe";
proc.StartInfo.Arguments = "-lr";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
proc.Start();
proc.WaitForExit();
stopWatch.Stop();
TimeSpan elapsed = TimeSpan.FromMilliseconds((double)stopWatch.ElapsedMilliseconds);
Diese Methode habe ich fünf mal ausgeführt. Dabei ergab sich, auf meiner Maschine, ein Mittelwert von 55,638 Sekunden für 676 Elemente. Somit war die Referenz-Zeit ermittelt als auch die Anzahl der Elemente die gefunden werden mussten.
Als Container zum aufnehmen der gefundenen Daten, habe ich mich für eine NameValueCollection entschieden. Um das, pro Iteration, gefundene Name-Wert Paar in die Kollektion einzufügen, habe ich zwei verschiedene Wege getestet. Als ersten das direkte Anfügen des Schlüssel-Wert Paares als Zeichenfolgen mit der NameValueCollection.Add(String, String)-Methode. Als zweiten Weg das Erzeugen einer zweiten NameValueCollection und diese mit der NameValueCollection.Add(NameValueCollection)-Methode in die Haupt-Kollektion einzufügen. Da die statischen for und foreach Methoden der TPL mit Delegaten arbeiten, habe ich zwei Hilfsmethoden erstellt um diese als Delegaten zu nutzen. Folgend die beiden Hilfsmethoden AddToCollection(String) und GetNameValuePair(String).
Die Methode AddToCollection(String) ist vom Typ void und fügt das Schlüssel-Wert Paar als Zeichenfolge an eine, als Class Member instanziierte, NameValueCollection an.
private static void AddToCollection(string assemblyName)
{
AssemblyCacheInstallReferenceEnum instRefEnum =
new AssemblyCacheInstallReferenceEnum(assemblyName);
InstallReference instRef = instRefEnum.NextReference;
// prüfen ob eine InstallReferenz-Instanz übergeben wurde
if (instRef != null)
{
StringBuilder sb = new StringBuilder(255);
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefSchemaMsg,
InstallReferenceGuid.GetGuidSchemeName(instRef.GuidScheme));
sb.Append(" ");
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefIDMsg,
instRef.Identifier);
sb.Append(" ");
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefDescriptionMsg,
instRef.NonCanonicalData);
assemblyCollection.Add(assemblyName, sb.ToString());
}
else
{
// keine InstallReferenz gefunden, NULL anfügen
assemblyCollection.Add(assemblyName, null);
}
}
Die Methode GetNameValuePair(String) ist vom Typ NameValueCollection. Diese zurückgegebene Kollektion wird an eine, in der aufrufenden Methode instanziierte, Kollektion angehängt.
private static NameValueCollection GetNameValuePair(string assemblyName)
{
NameValueCollection collection = new NameValueCollection(1);
AssemblyCacheInstallReferenceEnum instRefEnum =
new AssemblyCacheInstallReferenceEnum(assemblyName);
InstallReference instRef = instRefEnum.NextReference;
// prüfen ob eine InstallReferenz-Instanz übergeben wurde
if (instRef != null)
{
StringBuilder sb = new StringBuilder(255);
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefSchemaMsg,
InstallReferenceGuid.GetGuidSchemeName(instRef.GuidScheme));
sb.Append(" ");
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefIDMsg,
instRef.Identifier);
sb.Append(" ");
sb.AppendFormat(
CultureInfo.CurrentCulture,
Resources.AsmRefDescriptionMsg,
instRef.NonCanonicalData);
collection.Add(assemblyName, sb.ToString());
}
else
{
// keine InstallReferenz gefunden, NULL anfügen
collection.Add(assemblyName, null);
}
return collection;
}
Als Container welcher die Namen der Assemblies im GAC enthält, wird eine ReadOnlyCollection vom Typ string verwendet. Da die Erzeugung einer solche Kollektion bereits in der Klasse als öffentliche Methode vorhanden ist, wird diese einfach benutzt um eine Aufzählung der benötigten Assemblies zu erhalten. Nun braucht nur noch durch diese Aufzählung iteriert zu werden, und der jeweilige Rückgabewert wird an eine der beiden Methoden übergeben.
Um zu ermitteln ob die parallele Methode überhaupt einen Vorteil bringt, muss zunächst einmal die benötigte Zeit der sequenziellen Verwendung ermittelt werden. Wie schon für gacutil.exe wurde auch hier der Mittelwert aus fünf Durchgängen ermittelt. Wie bereits oben beschrieben ist dies nur eine einfache Iteration. Als einfachste Möglichkeit bietet sich hier eine foreach Schleife an.
// Collection mit Assemblies füllen die mit
// assemblyName übereinstimmen
assemblyList = GetAssemblies(assemblyName);
foreach (string asmName in assemblyList)
{
// je nach verwendeter Methode auskommentieren
//AddToCollection(asmName);
assemblyCollection.Add(GetNameValuePair(asmName));
}
Als Mittelwerte habe ich für die Methode AddToCollection(String) 43,338 Sekunden und für die Methode GetNameValuePair(String) 43,678 Sekunden ermittelt. Für 676 angefügte Elemente ist die Differenz von ca. 0,3 Sekunden zu vernachlässigen. Es zeigte mir aber auch, dass es faktisch keinen Unterschied bedeutet ob nun das Schlüssel-Wert Paar als zwei Zeichenfolgen oder als NameValueCollection angefügt werden.
Vor dem Erscheinen der Juni 2008 CTP des ParallelFX hatte ich bereits die Dezember 2007 CTP der selbigen genutzt. Ich wollte natürlich wissen ob sich in Sachen Performance etwas getan hatte. Also habe ich als erstes die Dezember 2007 CTP zum Testen der Parallelisierung verwendet. Als Container für die Assemblynamen wurde die gleiche ReadOnlyCollection wie in der sequenziellen Methode verwendet. Zum parallelen iterieren verwende ich die statische foreach Methode der Parallel Klasse. Hier das Code-Konstrukt der verwendeten Methode:
// Collection mit den Namen aller Assemblies im GAC erzeugen
assemblyList = GetAssemblies(null);
var exceptions = new ConcurrentStack<Exception>();
Parallel.ForEach<string>(
assemblyList,
delegate(string asmName)
{
try
{
// je nach verwendeter Methode auskommentieren
//AddToCollection(asmName);
assemblyCollection.Add(GetNameValuePair(asmName));
}
// zum testen werden die Ausnahmen nicht unterschieden
catch (Exception ex)
{
exceptions.Push(ex);
}
});
// prüfen ob Ausnahmen abgefangen wurden
if (!exceptions.IsEmpty)
{
throw new AggregateException(exceptions);
}
Die Verwendung der Parallel-Klasse aus der Dezember 2007 CTP ergab für die Methode AddToCollection(String) einen Mittelwert von 39,316 Sekunden und für die Methode GetNameValuePair(String) 38,495. Beide Methoden brachten einen Geschwindigkeitsvorteil von rund 4 Sekunden. Wie ich jedoch Eingangs darauf hingewiesen habe, eignen sich Aufgaben mit intensiven E/A-Operationen nicht besonders zur Parallelisierung.
Um zu sehen was sich in der Juni 2008 CTP des ParallelFX getan hatte, wiederholte ich den Test mit der Parallel-Klasse aus der neueren CTP mit folgendem Ergebnis: die Methode AddToCollection(String) benötigte nur noch 36,495 Sekunden im Mittel. Auch die zweite Methode GetNameValuePair(String) war mit 36,662 im Mittel deutlich schneller geworden. Aus den anfänglichen rund 4 Sekunden Differenz zur sequenziellen Verarbeitung waren mittlerweile rund 7 Sekunden geworden. Bei rund 43,5 Sekunden als Basis ergeben die rund 36,5 Sekunden doch einen Vorteil von rund 16%.
Ich habe auf einen direkten Vergleich mit dem Ergebnis der gacutil.exe bewusst verzichtet da sie weder in verwaltetem Code erstellt wurde, noch ich irgendwelche Kenntnisse über die Implementierung der Fusion-API in der gacutil.exe besitze. Ich habe die Kennwerte der gacutil.exe lediglich ermittelt um einen Wert zu haben an dem ich mich orientieren kann und um die Anzahl der zu erwartenden Elemente zu kennen. Was hilft die beste Methode, wenn sie falsche Ergebnisse, in meinem Fall die Anzahl der Assemblies, liefert.
In der Zusammenfassung ergibt sich für mich folgendes Bild:
- Als Aufgabe eine Operation die sich nur sehr bedingt zur Parallelisierung eignet.
- Ohne nennenswerten Mehraufwand eine parallele Lösung gefunden.
- Einen Geschwindigkeitsvorteil von rund 16% erzielt, mit einer CTP welche mit Sicherheit noch nicht optimiert ist.
Ob nun in Zukunft vermehrt von der Parallelisierung Gebrauch gemacht wird? Ich weis es nicht. Von meiner Warte aus kann ich nur sagen: Mit dem Parallel-Erweiterungen hat uns das ParallelFX-Team ein einfach zu handhabendes und sehr wirkungsvolles Werkzeug zur Verfügung gestellt. Falls jemand einmal Probleme mit der Parallel-Bibliothek haben sollte helfen die Mitglieder des Teams gerne im MSDN-Forum. Ich kann aus eigener Erfahrung sagen, dass mir dort schnell und kompetent geholfen wurde.
Ob sich nun der einzelne mehr mit der Parallelisierung seiner Aufgaben auseinandersetzt bleibt ihm selbst überlassen. Ich werde es auf jeden Fall tun.
HowToCode "YouRead": …eigentlich heisst es "ReadYou"
06.06.2008 19:11:02
|
Robert Mühsig
Da hat sich wohl der Fehlerteufel eingeschlichen - in den letzten beiden Blogposts war immer von “YouRead” die Rede, dabei heisst es eigentlich (jedenfalls ist diese Domain jetzt dafür gedacht
“ReadYou“.
Spricht sich auch deutlich einfacher
(und der Titel war auch bereits bei dem UI Prototyp zu sehen)
Der Fehler wurde mir bewusst, als ich voller Stolz meiner Freundin berichtet habe, dass ich nun mit “YouRead” angefangen hab.
Naja, Namen sind am Ende auch Schall und Rauch - freuen wir uns also nun auf viele “ReadYou” Blogposts
ShareThis
Social Linkkram
06.06.2008 17:21:22
|
Albert Weinert
Ich habe auf der rechten Seite mal ein paar Buttons mit links zu Social Networks (On- und Offline) hinzugefügt wo ich mehr oder weniger aktiv bin.

In den wohlverdienten Urlaub
06.06.2008 00:02:00
|
Rainer Schuster
Nachdem nun meine Probezeit im neuen Job vorbei ist, ich am Samstag kirchlich Heirate und danach für einen schönen Rundtripp nach Italien fahre, um zwei Wochen lang durch die Toskana mit meiner Frau unterwegs zu sei, möchte ich mich bis dahin bei allen verabschieden.
Um die Wartezeit etwas zu verkürzen hier meine Planung für die Zeit danach:
- An einem Community Projekt arbeiten, dass ich schon vor einiger Zeit angefangen habe. Das muss mal voran gehen (Details folgen, wenn es soweit ist).
- Einen ausführlichen Erfahrungsbericht zum neuen Sandcastle Help File Builder der eine tolle neue Unterstützung für zusätzliche Hilfedateien mitbringt. Ich bin begeistert! Die ersten Test habe ich schon erfolgreich hinter mir!
- Die erste Artikelserie über Dokumentation mit Sandcastle, Sandcastle Help File Builder und evlt. mit DocProject. Mit SHFB kenne ich mich schon sehr gut aus. DocProject folgt später, weil es eine super Integration ins Studio bringt.
Installation (gab es schon)
- Konfiguration (Einrichten der Programme zur benutzung)
- Erklärung der einzelnen Einstellungsmöglichkeiten
- Besonderheiten, Fähigkeiten, Einschränkungen und Best Practices
- Als Beispielapplikation weiß ich noch nicht was kommt (vielleicht das Projekt von Rober Mühsig, da muss ich mit ihm Rücksprache halten)
- Ich habe schon mit dem Gedanken gespielt, SHFB als VSpackage zu
refaktorieren, d.h. den bestehenden Code so in Interfaces zu zerteilen
und umzubauen, dass es sowohl stadalone als auch als VSpackage benutzt
werden kann. Daher will ich mich mehr mit Visual Studio Extensibility (VSX) beschäftigen und hier vielleicht den ein oder anderen Artikel schreiben. Über das Text Templating Transformation Tool (kurz T4) werde ich auf jeden Fall kurz berichten.
- UnitTesting, TDD (Pex, MbUnit V3, Gallio)
Bis dann.
Rainer
HowToCode "ReadYou": Was soll das System denn leisten? - Gedanken an die Anforderungen
05.06.2008 23:04:51
|
Robert Mühsig
In dem letzten “ReadYou” Post ging es allgemein um den Gesamtplan - als erstes möchte ich nochmal komplett ohne Code arbeiten und auch keine großen Gedanken zur Architektur machen.
Hier geht es um die Anforderungen die ich an das System habe. Neben den bereits gestellten Qualitätsanspruchen (Source Control, Tests, Dokumentation) sollten auch gewisse Grundfunktionen enthalten sein.
Wichtiger Hinweis: Ich werde die Anforderungen bewusst “simpel” fassen - im professionellen Umfeld sollte an dieser Stelle besonders viel mit dem Kunden geredet werden um herauszufinden, was er eigentlich will!
Was genau muss die Software/Plattform leisten?
Bilder sagen manchmal mehr als tausend Worte (und vor allem empfinde ich es dann meist viel logischer, wie das hinterher aussehen muss):
Aufmerksamen Lesern des Blogs sollte dieses Bild aus dem UI Prototyping mit Powerpoint bekannt vorkommen.
Ich liste jetzt mal alle Funktionen auf:
- User-Bereich:
- Login/Logout/Register/Password-Recovery
- Admin hat Management-Oberfläche
- User kann Profildaten speichern
- User sollte sich auch mit Open ID, Windows Live ID etc. anmelden können
- User kann andere User suchen etc.
- User kann Bücher anlegen (später evtl. auch Blogs)
- “Meine Seite” ähnlich wie StudiVZ Home
- Community - “Gruppen” etc.
- Bücher-Bereich:
- Anlegen / Löschen / Managen
- Bewerten
- Taggen
- Kategorisierung der Bücher
- Amazon-Anbindung
- Rezessionen verfassen (oder man nimmt die Amazon-Rezessionen über die API
)
- Allgemeines:
- Aktive User ähnlich wie in den ASP/MSDN Foren
- Neuste Bücher wie bei YouTube “Videos right watched now…”
Um es kurz zu sagen: Typische Communityseite - wobei ich die Anforderungen hier nicht so eng fasse.
Eine interessante Sachen die ich gerne einbauen würde:
- Providermodell für Authentifizierung & Userdaten
Das ASP.NET Membership-System gefällt mir nicht wirklich - es ist nett, hat aber seine Tücken und ist bei manchen Sachen (Profiles z.B.) nicht wirklich schön.
Zudem möchte ich die Authentifzierung von den eigentlichen Nutzerdatenzugriff trennen, weil ich bislang häufig bei Projekten folgendes Szenario hab:
- Oracle-DBs mit wilden Benutzerdaten
- AD / LDAP als Authentifizierung, allerdings stammen die wirklichen Userdaten dann aus einer anderen DB
- Profildaten etc. werden extra gespeichert
Insbesondere durch die Anforderung, die ich mir selbst gestellt habe, als Authentifizerung auch OpenID, Windows Live etc. zu unterstützen, wären die Userdaten und die Userauthentifizierung sowieso getrennt.
“AuthenticationRepository” & “UserRepository”:
Ich bin sehr angetan von Rob Conerys Architektur mit den Pipes & Filters Modell und dem IQueryable Interface.
Als momentane Idee steht daher solch eine “Grobe”-Architektur:
Diese “Architekturgedanken” sind hier für die Erklärung der Anforderung zu verstehen. Code etc. wird es erst später geben
Data:
Hier versteh ich die verschiedenen Datenquellen - z.B. eine Oracle-DB, eine SQL-DB, Windows Live oder OpenID (wenn es um die Authentifizierung geht).
Repository;
Hier ist die Datenzugriffsschicht - als wäre hier angenommen LINQ to SQL/ADO.NET EF/NHibernate/SubSonic oder die Windows Live API etc. einzubauen.
Service:
Der Service sollte so lose wie möglich an das “Backend” gekoppelt sein - ich denke dies hier ist ein nettes Einsatzgebiet von Dependency Injection. Dieser Serivce wird im Frontent aufgerufen und gibt das an die entsprechenden Repositories weiter.
Mein Wunschtraum:
Der Idealzustand dieser Plattform wäre, wenn ich an einer Codestelle oder über Konfiguration mein “Datenquellen” angeben kann, z.B.:
Variante A)
Nimm als Authentifizierungsquelle und Userquelle den SQL Server.
Variante B)
Nimm als Authentifizierungsquelle das Active-Directory und als Userquelle die Oracle DB
Am Ende muss man “nur” einen entsprechenden Provider bereitstellen und ich will Service nichts großes ändern müssen - ob das so klappt, wage ich jetzt mal zu bezweifeln, da die Anmeldedaten auch unterschiedlich sind - aber das wird eine interessante Sache für die nächsten Blogposts
Alles klar?
Kunde: “Falls Sie noch Fragen haben, melden Sie sich einfach. Ich denke, dass ist eine machbare kleine Anwendung - das dauert bestimmt nicht lange.”
Programmierer:
Feedback:
Auch wenn ich einen möglichst “professionellen” Ansatz verfolgen möchte, will ich hier möglichst bald euch Code präsentieren. Die Rubrik heisst ja auch “HowToCode” und nicht “HowToRequirementsManagement”, daher sei mir hoffentlich die spärlichen Anforderungen verziehen
Aber wenn ihr noch Vorschläge habt (was unbedingt mit rein müsste, und was man mit bedenken sollte), dann immer her damit.
Ausblick:
Die Idee mit der Authentifizierung/Userdata-Sache werde ich sicherlich erstmal prototyisch das nächste mal in Angriff nehmen und genauer auf die anderen Architekturpunkte eingehen.
ShareThis
TechEd Orlando 2008 – Mittwoch: IBM-Angebote für TechEd-Teilnehmer
05.06.2008 20:49:16
|
Mathias Raacke
Heute morgen gab es einige kleinere logistische Probleme – unser Hotel liegt am Ende
der Route, die die Shuttlebusse zur TechEd abfahren. Die Busse waren immer schon voll,
bevor sie unser Hotel erreicht haben, so dass ich über eine halbe Stunde auf einen
freien Bus warten musste.
Statt der TechEd Busse gab es aber zwei Busse von IBM – von IBM gibt es hier parallel
zur TechEd ebenfalls eine Veranstaltung für Entwickler, und IBM versucht wohl, TechEd
Besucher auf die IBM Konferenz zu locken. Vor den IBM Bussen heute morgen standen
Hostessen mit einem Schild, dass TechEd Teilnehmer kostenlos an der IBM Keynote teilnehmen
können. Außerdem habe ich später noch erfahren, dass man mit dem TechEd Konferenzbadge
auch an der IBM Party heute Abend teilnehmen kann. Schade dass ich keine Zeit habe,
das hätte ich mir ja gerne mal angesehen… ;).
Heute war ich nur für Hands-on Labs eingeteilt. Bis jetzt habe ich den Eindruck, dass
die HOL dieses Jahr deutlich besser und fehlerfreier sind als letztes Jahr, und dass
es deshalb deutlich weniger Fragen gibt. Hauptsächlich habe ich den Leuten bisher
erklärt wie unsere Hands-on Lab Startsoftware funktioniert und was man damit machen
kann. Inhaltliche Fragen gab es eher selten.
Ich hatte heute “schon” ab 16:30 Uhr frei und somit noch 90 Minuten Zeit für viele
interessante Gespräche im Technical Learning Center, wo es zu so ziemlich jedem (für
Entwickler relevantem) Produkt einen Stand mit Mitarbeitern der jeweiligen Product
Group gibt. Da habe ich dann z.B. Erfahren, dass das in der Keynote vorgestellte Layer
Diagram wohl schon in der nächsten CTP Version von Rosario enthalten sein wird. Das
wird auf jeden Fall eine CTP die ich mir näher ansehen werde. Außerdem habe ich am
Team System Stand eine Demo gesehen, bei der automatisch aus Code Sequenzdiagramme
generiert wurden. Das sieht alles sehr vielversprechend aus.
Heute Abend ist MCT Party, aber leider werde ich wohl nicht hin gehen können weil
ich noch meine Präsentation für Samstag vorbereiten muss.
WPF, Layouts und verschwundene Scrollleiste
05.06.2008 13:35:11
|
Norbert Eder
Das Problem
Ich habe auf meinem Fenster einige Elemente angeordnet. Darunter auch eine ListView. Diese hatte anfangs eine Scrollleiste, aber jetzt ist diese verschwunden? Warum?
Die Lösung
Diese und ähnliche Fragen werden sehr häufig gestellt. In den meisten Fällen liegt es daran, dass die verwendeten Layout-Elemente nicht gut genug bekannt sind und daher ein Fehlverhalten interpretiert wird, wo eigentlich gar keines ist.
Ein sehr verdächtiges Element ist in diesem Zuge das
StackPanel. Es verändert seine Größe abhängig der eingebetteten Elemente.
Hier ein kleiner Beispielfall um dies näher zu beschreiben: Wir gehen davon aus, dass es ein StackPanel gibt. Dieses hat als Kindelement eine
ListView. Letztere ist an eine Liste gebunden, welche einige hundert Elemente besitzt. Wird nun die Liste gebunden, vergrößert sich die ListView mit jedem Element das hinzugefügt wird. Bei einigen hundert Elementen kann man davon ausgehen, dass nicht mehr alle am Bildschirm angezeigt werden können und deswegen eine Scrollbar durchaus sehr sinnvoll wäre. Tatsächlich ist es nun so, dass sich das Elternelement, also das StackPanel, an die Größe der ListView anpasst und es somit gar nie notwendig wird, die Scrollbar anzuzeigen.
<DockPanel x:Name="ParentDock" Margin="8"
LastChildFill="True">
<StackPanel DockPanel.Dock="Top">
<Button Content="Click me first"/>
<Button Content="Do not click me"/>
<ListView x:Name="DemoBox">
<ListView.View>
<GridView>
<GridViewColumn/>
<GridViewColumn/>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</DockPanel>
In diesem Beispiel ist das StackPanel zwar in ein DockPanel eingebettet, verändert aber dennoch seine Größe, da der Inhalt wesentlich größer ist. So sieht es aus:
In diesem Fall muss auch gar nicht viel verändert werden. Damit die ListView zu ihrer Scrollbar kommt, ist diese lediglich aus dem StackPanel heraus zu nehmen:
<DockPanel x:Name="ParentDock" Margin="8"
LastChildFill="True">
<StackPanel DockPanel.Dock="Top">
<Button Content="Click me first"/>
<Button Content="Do not click me"/>
</StackPanel>
<ListView x:Name="DemoBox">
<ListView.View>
<GridView>
<GridViewColumn/>
<GridViewColumn/>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
</DockPanel>
Damit ist nun das
DockPanel für die ListView zuständig und beschränkt deren Größe. Dadurch wird die Scrollbar sichtbar. So siehts aus:
Fazit
Durch dieses Problem muss sich jeder durchkämpfen, der mit WPF beginnt. Die Verhaltensweisen sind unterschiedlich zu Windows Forms, in einigen Fällen ähnlich zu ASP.NET. Wichtig ist, sich mit den jeweiligen Layout-Elementen zu beschäftigen und zu lernen, wie sie mit Inhalten umgehen. Mit ein wenig Spielerei sollten dann zukünftig derartige Probleme vermieden werden können. Es warten ohnehin genug andere
Was macht eigentlich so eine T-Systems MMS?
04.06.2008 22:13:47
|
Robert Mühsig
Vor kurzem hat Oli ja bereits von unseren Mitarbeitergesuch geschrieben. Wer sich nun fragt, was wir eigentlich im Groben den ganzen Tag machen, dann schaut euch einfach mal das Video an:
… das und natürlich noch viel mehr
Ein nettes (Promo-) Video
Weitere Videos findet man auf dem T-Systems MMS YouTube Channel.
ShareThis
Sanfte VB6-Migration
04.06.2008 15:16:43
|
Jens Häupel
Microsoft stellt Ressourcen und Tools für die Nutzung von .NET in VB6 Anwendungen und die sanfte Migration bereit
Der Extended Support für die Visual Basic 6.0-Entwicklungsumgebung endete im April. Die Runtime von VB6 wird jedoch unter Vista und Windows 2008 weiter unterstützt. Viele Entwickler verwenden immer noch die VB6-Entwicklungsumgebung (IDE) und haben eine signifikante Codebasis, die gewartet werden muss.
Mit dem Interop-Forms-Toolkit können VB6 Entwickler die Vorteile von .NET und Visual Basic 2008 nutzen, um Ihre VB6-Anwendungen zu pflegen, und auch .NET-Funktionalitäten in diese VB6 Anwendungen zu integrieren. Dadurch lassen sich neue Szenarien wie etwa Onlinebestellungen, Office Integration oder die Einbindung von MapPoint sowie anderen Online-Diensten einfach realisieren.
Durch den konsequenten Einsatz des Toolkits sind Entwickler auch in der Lage, ihre Anwendungen Formular für Formular auf .NET umzustellen und diese jederzeit auszuliefern (auch im hybriden Zustand .NET & VB6). Entwicklern wird empfohlen, ihre Anwendungen mit dieser Methode innerhalb des Vista-Support-Lifecycle auf .NET zu portieren. Die zahlreichen Lernvideos machen die Nutzung von .NET in VB6 sowie das Thema Vista-Kompatibilität zum Kinderspiel.
Alle Infos und Lernvideos finden Sie im Visual Basic 6 Resource Center
Celebrate What's Right With The World
04.06.2008 12:11:00
|
Jens Häupel
Sind nicht besonders wir Deutsche dafür bekannt, das Negative in der Sache herauszukehren? Die Tasse ist halb leer, nicht halb voll, oder? Gefragt nach dem Urlaub, antworten wir als erstes: ".. ja aber das Essen war schlecht und das Wetter auch nicht gut...". Machen wir uns damit nicht selbst das Leben schwer? Think positive! - eine Floskel?
Dewitt Jones (weltklasse Fotojournalist für National Geographic) hat einen Film dazu gedreht. Darin erzählt er, was ihn in all den Jahren am meisten inspiriert hat, wie er gelernt hat, die Welt zu sehen. Und was ein gutes Bild von einem Top Bild unterscheidet. Wir müssen lernen zu sehen.
Sehenswert auch für Nicht-Fotografen.
HowTo: Generisches speichern und laden von XML Dateien bzw. wozu sind Generics gut?
04.06.2008 11:05:58
|
Oliver Guhr
Immmer wenn ich eine Xml Datei lesen oder schreiben will fange ich wieder an das Code-Snippet dafür zu suchen und an meine Objekttypen anzupassen. Also habe ich mir jetzt mal eine generische Version geschrieben. Das T steht dabei für den noch unbekannten Typ der erst zur Laufzeit übergeben wir.
public static void Save<T>(String path, T obj)
{
XmlSerializer Serializer = new XmlSerializer(typeof(T));
FileStream Stream = new FileStream(path, FileMode.Create);
Serializer.Serialize(Stream, obj);
Stream.Close();
}
public static T Load<T>(String path)
{
XmlSerializer Serializer = new XmlSerializer(typeof(T));
StreamReader Stream = new StreamReader(path);
T myObject = (T)Serializer.Deserialize(Stream);
Stream.Close();
return myObject;
}
Der Zugriff erfolgt so:
// Daten
String TestString = "Hallo Xml Welt";
//schreiben..
Save<String>("C:\\test.xml", TestString);
//und lesen
Debug.WriteLine(Load<String>("C:\\test.xml"));
46 Tutorials zum Thema ASP.NET AJAX Control Toolkit
04.06.2008 08:28:00
|
Jürgen Gutsch
Silverlight 2 Beta 2 kommt diese Woche
04.06.2008 08:14:59
|
Oliver Scheer
Heute in der Keynote der Microsoft TechEd kündigten Bill Gates und Soma Somasegar an, dass Silverlight 2 Beta 2 im Verlauf dieser Woche veröffentlicht wird und als kostenloser Download zur Verfügung stehen wird.
Neue Highlights in Silverlight 2 Beta 2:
Optimiertes UI Framework: Beta 2 bringt deutliche Verbesserungen im Bereich Animationen, Fehlerverarbeitung und –reporting, Automatisierung, Barrierefreiheit, Tastaturunterstützung und bei der Performance. Die Kompatibilität zwischen Silverlight und WPF wurde zudem erweitert.
Erweiterte Controls: Silverlight 2 Beta 2 enthält ein neues „Templating Modell“ namens Visual State Manager, mit dem sich komfortabel Templates (Vorlagen) für Controls anlegen lassen. Außerdem neu sind TabControl, Text Wrapping, Scrollbars für Textboxen und neue DataGrid-Funktionen wie Autosize, Reorder, Sort, sowie ebenfalls deutliche Performancegewinne bei Controls. Controls sind nun in die Runtime integriert und müssen nicht mehr mit der Anwendung ausgeliefert werden.
Verbesserte Netzwerkunterstützung: Zu den neuen Netzwerkfunktionen in Beta 2 gehören domainübergreifender Zugriff und erweiterte Sicherheitsfunktionen, Uploadunterstützung für Webclients und Duplexkommunikation („Push“ vom Server zum Silverlight-Client).
Rich Base Class Library: Beta 2 verfügt über verbesserte Threadingfähigkeiten, LINQ-to-JSON, ADO.NET Data Services, bessere Unterstützung für SOAP, sowie viele weitere Verbesserungen die Networking und Datenverarbeitung deutlich komfortabler und einfacher machen.
Verbessertes Deep Zoom: Beta 2 führt ein neues XML-basiertes Dateiformat für Deep Zoom Image Tiles (Bildkacheln) ein, sowie das neue MultiScaleTileSource -- somit können bestehende Bild-/Kacheldatenbanken mit Deep Zoom verwendet werden.
Silverlight 2 Beta 2 wird im Laufe der Woche veröffentlicht und kann dann hier herunter geladen werden: http://www.silverlight.net
Außerdem ab sofort verfügbar ist Expression Blend 2.5 June Preview: http://www.microsoft.com/expression/try-it
Silverlight 2 ermöglicht schnelle Vektorgrafiken, flüssige Animationen, Audiointegration, kostengünstige Videopräsentation und Videostreaming bis hin zu HD-Video im Web. Damit lassen sich moderne Benutzeroberflächen und faszinierende Multimediaerlebnisse schaffen, die es Anwendern ermöglichen Videos in HD-Qualität gemeinsam mit Freunden online zu erleben. Ebenso ist es die optimale Plattform, um Businessanwendungen entwickeln, die Geschäftsinformationen dynamisch und plattformunabhängig im Webbrowser visualisieren (eine faszinierende Silverlight-Beispielanwendung die viele der Funktionen von Silverlight demonstriert ist hier verfügbar: http://www.mscui.net/PatientJourneyDemonstrator).
TechEd Orlando 2008 – Dienstag: Bill Gates Keynote
04.06.2008 02:22:47
|
Mathias Raacke
Die TechEd begann heute morgen mit dem letzten großen Auftritt von Bill Gates. Ich
hätte da eigentlich etwas besonderes erwartet, aber stattdessen war es eine “Standard-Keynote”
ohne irgendwelche größeren Überraschungen was die Präsentation der Keynote betrifft.
Es gab eine neue Version des Videos von BillGs letztem Tag bei Microsoft mit einigen
neuen Szenen. Da war die Keynote letztes Jahr mit dem Schauspieler aus “Zurück in
die Zukunft” + Auto besser.
Inhaltlich gab es bis auf wenige Ausnahmen keine besonderen Überraschungen, das meiste
davon hat Heise zusammengefasst (wobei
in dem Artikel allerdings gerade die spannenden Ankündigungen fehlen). Wenn ich mir
da den letzten Teil des Artikels ansehe hat allerdings entweder Heise das Sync Framework
nicht verstanden, oder ich verstehe es falsch… Jedenfalls wäre mir neu, dass das Sync
Framework für Web-Clientsoftware gedacht ist. (oder verstehen die
darunter etwas anderes als ich?)
Die spannensten Ankündigungen tauchen im Heise Artikel gar nicht auf: die erste CTP
von Oslo soll wohl zur PDC erscheinen. Oslo wure in der Keynote mehrfach erwähnt,
und insbesondere auch oft im Zusammenhang mit Model Driven Development. Außerdem wurden
einige neue Modellierungsmöglichkeiten in Visual Studio vorgestellt, wobei mir insbesondere
das Application Layer Diagramm sehr gut gefalllen hat. Damit kann man einzelne Assemblies
verschiedenen Schichten einer Anwendung zuordnen und auch automatisch überprüfen,
dass es keine Abhängigkeiten zwischen Schichten gibt, die nicht direkt aufeinander
zugreifen sollen (z.B. von Präsentationsschicht auf Datenbankschicht). Als weiters
neues Diagramm gibt es ein Diagramm, dass Abhängigkeiten zwischen Assemblies und Klassen
anzeigt.
Gegen Ende der Keynote gab es eine Demo zu Robotics Studio. Dafür ist ein Roboter
auf die Bühne gefahren, der auf nur 2 Rädern fährt und dabei das gleichgewicht selbstständig
hält. Als “Gesicht” hatte er einen Bildschirm mit einem Foto von Steve Ballmer, und
auf der Bühne hat er dann Steves berühmten “Developers, Developers, Developers” Ausruf
nachgemacht. Ein Video
vom “Ballmerbot” gibt es im Blog von Steve Clayton.
Während der TechEd saß ich zufällig neben Simon Guest,
einem relativ bekannten Microsoft Blogger. War interessant mal ein Gesicht zum Blog
kennenzulernen.
Leider hatte ich meine Kamera heute im Hotel vergessen, so dass ich keine Fotos von
der Keynote und insbesondere von den neuen Modellierungsmöglichkeiten machen konnte
:(.
Nach der TechEd hatte ich heute drei Instructor-Led Labs, wobei ich einmal selbst
präsentiert habe und zwei mal andere TLGs bei ihren Labs unterstützt habe. Das erste
Lab war ein Lab zu C# 3.0, danach kam mein Lab zu Windows Mobile, und am Ende noch
eines zu Windows Embedded und dem Platform Builder (ein Thema, von dem ich Null Ahnung
habe – allerdings haben wir hier zu wenig TLGs die sich damit auskennen, und mit etwas
Grundwissen zu Windows Mobile liege ich wohl noch am nächsten am Thema und wurde dem
Lab deshalb zugeteilt).
Ich denke meine eigene Präsentation ist recht gut gelaufen, allerdings hatte ich bisher
noch keinen Zugriff auf das Teilnehmerfeedback. Morgen erfahre ich da hoffentlich
mehr. Jedenfalls hatte ich 42 Teilnehmer, und die meisten davon wollten nach Ende
des Labs noch bleiben und weiter arbeiten (was allerdings nicht möglich war, da es
danach gleich ein weiteres Lab im gleichen Raum gab).
Ich bin immer noch nicht so richtig auf die neue Zeitzone eingestellt, vor allem Abends
bin ich immer noch sehr müde. Das ist super schade, da ich dadurch schon einige Partys
verpasst habe. Mal sehen ob ich morgen fit genug bin oder ob ich auch morgen wieder
früh ins Hotel zurück fahren werde.
Eine weitere Zusammenfassung der Keynote gibt es im Blog von Somasegar:
http://blogs.msdn.com/somasegar/archive/2008/06/03/on-stage-at-the-teched-2008-keynote.aspx
HowToCode "ReadYou": Community-getriebene professionelle Applikationsentwicklung
03.06.2008 22:19:21
|
Robert Mühsig
Der Posttitel klingt schon mal recht hochgegriffen und es ist für mich auch eine Art Experiment und hoffe, dass es (früher oder später) auch Feedback gibt
Was ist “ReadYou”?
Trotz des “Web 2.0″-Zeitalters mag ich immer noch Bücher - seien es Fachbücher oder andere Romane. Da ich allerdings langsam den Überblick verliere und es meiner Freundin ähnlich geht, muss eine Plattform her, wo man solche “Bücherbestände” möglichst cool und einfach managen kann (und natürlich die ganzen anderen Community-Sachen die üblich sind).
ReadYou ist daher momentan mein Projektarbeitstitel - am Ende soll unter www.readyou.de eine kleine, schicke Web 2.0 Anwendung stehen.
Das Thema ist jetzt nicht unbedingt jedermanns Sache, allerdings sind meist die “Grundzüge” einer solchen Applikation immer gleich - um ReadYou mal mit markanten Web 2.0 Schlagwörtern zu beschreiben:
Ganz guten würden zudem noch Blogs in diesen Kontext reinpassen - aber das ist eine andere Geschichte
Aha… was hat das mit uns zutun?
Ich bin ein großer Fan von Rob Conerys MVC Storefront und hab bei seinen Videos einiges gelernt:
Da ich zumeist noch das Problem bei privaten Projekten hab, dass ich irgendwann die Lust verliere, mach ich es diesmal von Anfang an “offen” für jeden - damit ich es nicht irgendwann auf meiner Platte verliere. Dabei soll nicht nur der Source-Code “offen” sein, sondern auch warum ich diese und jene Entscheidung treffe oder warum ich das Tool nehmen möchte.
Es soll eine möglichst professionelle Applikation rauskommen, welche eine möglichst robuste Architektur aufweisst, gut getestet ist und auch (das leidige Thema der Entwickler) sogar dokumentiert ist - also ein möglichst professioneller Ansatz.
Da ich natürlich kein Experte in TDD, Dokumentieren, Toolauswahl, Architektur etc. bin, ist Feedback besonders wichtig
Was soll das bringen?
Am Ende soll möglichst eine Art “Leitfaden” entstehen (die Applikation ist quasi das Nebenprodukt), den Anfänger ebenfalls beschreiten können - und auch verstehen, warum diese und jene Entscheidungen getroffen wurden und auch (was sicherlich passieren wird), dass manche Entscheidungen vielleicht unklug waren.
Es sollte nicht als pure deutsche Kopie von Robs Videos zu sehen sein (ich glaub nicht, dass ich so gute Screencasts überhaupt machen könnte), sondern ein Lernexperiment für jedermann - vergleichbar mit einem größeren HowTo - diesmal “HowTo code ReadYou”
Themen/ToDo´s die ich mir vornehme:
- Welche Anforderungen hat das System:
Anforderungsmanagement ist ein wichtiger Punkt bei einem Software-Projekt. Da ich hier allerdings selber der Kunde bin, werde ich meine Anforderungen und ungefähren Designvorstellungen selber schreiben - Abschätzungen oder ähnliches werden aber nicht gemacht
Anhand dieser Anforderungen muss eine entsprechende Architektur entworfen werden - dabei werde ich mir sicherlich die eine oder andere Idee bei Rob nochmal genauer anschauen.
Als Source Control ist momentan Codeplex meine erste Wahl (TFS Infrastruktur). Hierbei muss ich mal schauen, wie weit man es da treiben kann - Stichwort Continuous Integration). Builds sollten möglichst automatisch ablaufen können - daher werde ich mich an dieser Stelle MSBuild widmen. Hier bin ich mir noch etwas unsicher was Codeplex bietet und wie ich das am cleversten anstelle - aber an dem Punkt bin ich ja noch nicht
Ich versuche möglichst mich nach dem TDD Mantra “Test-First” zu richten - sodass eine möglichst robuste Applikation am Ende rauskommt. Auch Themen wie Dependency Injection, MSTest als Testframework, ASP.NET MVC nehm ich mir vor.
Da Source-Code möglichst dokumentiert sein sollte, soll auch hier mal von Anfang an daran gedacht werden - ich probier es mal mit Sandcastle (hier & hier gibt es einen guten “Überblick” über die neusten Versionen)
Feedback
Wie bereits oben erwähnt ist Feedback natürlich sehr wichtig - wenn ich aus eurer Sicht was vergessen hab, ihr das Konzept blöde findet oder was auch immer - (konstruktive) Krtik ist immer gut
Ich hoffe ich kann in den nächsten Tagen die ersten Themen/ToDo´s angehen
Kostenlose Lizenz von SmartInspect abzustauben
03.06.2008 21:38:43
|
Jan Welker
"SmartInspect is
an advanced logging tool for debugging and monitoring .NET, Java and Delphi applications.
It helps you to identify bugs, find solutions to customer problems and gives you a
clear understanding of how your software works in different environments. Whether
you need logging in the development phase, on production systems or at customer sites,
SmartInspect is the perfect choice."
Wer Lust hat, diese Software zu testen und einen Testbericht darüber zu schreiben,
sollte sich jetzt schnell im .NET-Forum.de anmelden
und auf diesen Thread antworten.
Nach dem Test kann die Lizenz behalten werden!
// Edit:
Der erste Testbericht wurde veröffentlicht:
http://dotnet-forum.de/KnowledgeBase/articles/2008/06/18/294-gurock-smartinspect-version-2-3.aspx
Sandcastle Help File Builder in neuer Version 1.7.0.0 erschienen
03.06.2008 16:59:51
|
Rainer Schuster
Passend zur neuen Version von Sandcastle (Mai08 CTP) gibt es seit gestern auch die neue Version 1.7.0.0 vom SHFB. Es gibt einige Änderungen in der Versionshistorie auf der offiziellen Dokumentationsseite vom SHFB. Die wichtigste Neuerung für mich ist wie schon in vorherigen Blogposts erwähnt, die Unterstützung für konceptuelle Hilfe (Conceptual Help) als MAML. Ich werde diese Funktion testen und Ende Juni einen ausführlichen Erfahrungsbericht mit einem Tutorial/Artikel geben.
Ihr dürft also alle gespannt sein. Wer es nicht abwarten kann, schnappt sich die neuen Version und probiert es selbst schon mal. Eines kann ich schon vorweg verraten: Das Ergebnis ist phänomenal.
Silverlight 2 Beta 2 kommt diese Woche
03.06.2008 13:47:00
|
Steffen Ritter
Heute in der Keynote der Microsoft TechEd kündigten Bill Gates und Soma Somasegar an, dass Silverlight 2 Beta 2 im Verlauf dieser Woche veröffentlicht wird und als kostenloser Download zur Verfügung stehen wird.
Neue Highlights in Silverlight 2 Beta 2:
- Optimiertes UI Framework: Beta 2 bringt deutliche Verbesserungen im Bereich Animationen, Fehlerverarbeitung und –reporting, Automatisierung, Barrierefreiheit, Tastaturunterstützung und bei der Performance. Die Kompatibilität zwischen Silverlight und WPF wurde zudem erweitert.
- Erweiterte Controls: Silverlight 2 Beta 2 enthält ein neues „Templating Modell“ namens Visual State Manager, mit dem sich komfortabel Templates (Vorlagen) für Controls anlegen lassen. Außerdem neu sind TabControl, Text Wrapping, Scrollbars für Textboxen und neue DataGrid-Funktionen wie Autosize, Reorder, Sort, sowie ebenfalls deutliche Performancegewinne bei Controls. Die meisten Controls sind nun in die Runtime integriert und müssen nicht mehr mit der Anwendung ausgeliefert werden.
- Verbesserte Netzwerkunterstützung: Zu den neuen Netzwerkfunktionen in Beta 2 gehören domainübergreifender Zugriff und erweiterte Sicherheitsfunktionen, Uploadunterstützung für Webclients und Duplexkommunikation („Push“ vom Server zum Silverlight-Client).
- Rich Base Class Library: Beta 2 verfügt über verbesserte Threadingfähigkeiten, LINQ-to-JSON, ADO.NET Data Services, bessere Unterstützung für SOAP, sowie viele weitere Verbesserungen die Networking und Datenverarbeitung deutlich komfortabler und einfacher machen.
- Verbessertes Deep Zoom: Beta 2 führt ein neues XML-basiertes Dateiformat für Deep Zoom Image Tiles (Bildkacheln) ein, sowie das neue MultiScaleTileSource -- somit können bestehende Bild-/Kacheldatenbanken mit Deep Zoom verwendet werden.
Silverlight 2 Beta 2 wird im Laufe der Woche veröffentlicht und kann dann hier herunter geladen werden: http://www.silverlight.net
Außerdem ab sofort verfügbar ist Expression Blend 2.5 June Preview: http://www.microsoft.com/expression/try-it
Silverlight 2 ermöglicht schnelle Vektorgrafiken, flüssige Animationen, Audiointegration, kostengünstige Videopräsentation und Videostreaming bis hin zu HD-Video im Web. Damit lassen sich moderne Benutzeroberflächen und faszinierende Multimediaerlebnisse schaffen, die es Anwendern ermöglichen Videos in HD-Qualität gemeinsam mit Freunden online zu erleben. Ebenso ist es die optimale Plattform, um Businessanwendungen entwickeln, die Geschäftsinformationen dynamisch und plattformunabhängig im Webbrowser visualisieren (eine faszinierende Silverlight-Beispielanwendung die viele der Funktionen von Silverlight demonstriert ist hier verfügbar: http://www.mscui.net/PatientJourneyDemonstrator).
TechEd Orlando 2008 – Montag (Pre-Conference)
03.06.2008 01:54:44
|
Mathias Raacke
Heute war mein erster “richtiger” Arbeitstag auf der TechEd. Es gab heute einige Pre-Conference
Vorträge und auch die Hands-on Labs waren schon geöffnet.
Dieses Jahr haben wir ca. 600 Computer in den Hands-on Labs, verteilt auf mehrere
Themengebiete. Ich bin gleich für 3 Bereiche eingeteilt: 1) Windows Mobile, 2) Web
and User Experience, Tools and Languages, 3) Windows and Frameworks, Development Practices.
Mobile ist ja eigentlich nicht so ganz mein Hauptthema, aber die meisten Fragen die
hier gestellt werden lassen sich auch mit Wissen zum “großen” .NET Framework beantworten.
Heute war auch noch nicht ganz soviel los wie wahrscheinlich ab morgen, die meisten
Teilnehmer werden erst ab morgen zur Hauptkonferenz anreisen. Dafür gab es die “üblichen”
kleineren technischen Probleme mit einigen Rechnern, so dass ich viel mit dem reporten
verschiedener Fehler beschäftigt war. Insgesamt laufen die Labs aber schon sehr gut
und größtenteils auch ohne Probleme.
Die Fotos habe ich heute morgen aufgenommen bevor die Hands-on Labs geöffnet wurden,
deshalb sieht es noch so leer aus.
TechEd Orlando 2008 – TLG Training am Sonntag
03.06.2008 01:38:27
|
Mathias Raacke
Sonntag war TLG Orientation, d.h. wir Technical Learning Guides wurden auf unsere
Aufgaben in den Hands-on Labs vorbereitet. Die Organisation war ja bereits letztes
Jahr super, aber dieses Jahr wurden einige Prozesse überarbeitet und verbessert.
Es war sehr interessant viele bekannte Gesichter vom letzten Jahr wieder zu sehen,
und auch viele neue TLGs kennen zu lernen die zum ersten Mal auf der TechEd arbeiten.
Dieses Jahr kann ich mich sogar mal auf deutsch unterhalten. Ich bin zwar immer noch
der einzige deutsche TLG, es gibt jetzt aber auch noch einen TLG aus Österreich.
TLG Training (leider etwas unscharf):
Wöchentliche Rundablage: ASP.NET MVC, .NET, ADO.NET Data Services, Silverlight, WPF…
02.06.2008 22:31:14
|
Robert Mühsig
ASP.NET MVC / ASP.NET:
.NET:
ADO.NET Data Services:
WPF / Windows Presentation Foundation / Silverlight:
Visual Studio:
Web:
Live Mesh:
Mix:
Gratis WinForm Controls - Free WinForm Controls
02.06.2008 21:32:00
|
Ozgur Aytekin
ComponentFactory bietet diverse Gratis WinForms Controls unter dem Namen Krypton Toolkit an. Diese Controls können gemäß Informationen auf der ComponentFactory Homepage auch Kommerziell eingesetzt werden.
Die URL für die Installationsdatei wird an die angegebene E-Mail Adresse geschickt. Während der Installation werden verschiedene Beispiel-Projekte und eine Beispiel-Applikation mit dem Namen Krypton Explorer installiert.
Mit Hilfe der Krypton Explorer können die verschiedene Controls getestet werden.

Innerhalb der Beispiel-Applikation kann der Entwickler auch die einzelne Eigenschaften der Controls ändern und den Verhalten des Controls testen.
Folgende Controls sind Bestandteil des Krypton Toolkits:
| Button - KryptonButton | ListBox - KryptonListBox |
| CheckButton - KryptonCheckButton | CheckedListBox - KryptonCheckedListBox |
| DropButton - KryptonDropButton | TextBox - KryptonTextBox |
| ColorButton - KryptonColorButton | RichTextBox - KryptonRichTextBox |
| CheckSet - KryptonCheckSet | ComboBox - KryptonComboBox |
| CheckBox - KryptonCheckBox | Panel - KryptonPanel |
| RadioButton - KryptonRadioButton | SplitContainer - KryptonSplitContainer |
| Label - KryptonLabel | DataGridView - KryptonDataGridView |
| LinkLabel - KryptonLinkLabel | ContextMenu - KryptonContextMenu |
| Form - KryptonForm | BorderEdge - KryptonBorderEdge |
| Group - KryptonGroup | HeaderGroup - KryptonHeaderGroup |
| Header - KryptonHeader | Palette - KryptonPalette |
| Command - KryptonCommand | |
Die SourceCode-Dateien dieser Controls kann auch gekauft und bei Bedarf angepasst werden.
URL: Download Krypton Toolkit 2.8.5

Visual Studio erweitern - Wie fange ich an?
02.06.2008 14:55:04
|
Rainer Schuster
Unter VSX versteht der versierte Anwender Visual Studio eXtensibility - wodurch sich das Akronym erklärt - also die Erweiterung der IDE. Auf der Suche nach einem geeigneten Editor für MAML, das von Microsoft mit Vista eingeführt wurde und als Grundlage für das neue Hilfesystem dient habe ich leider nicht viel gefunden. Hier entstehen für mich als unbedarften Leser zwei Fragen.
- Warum suche ich einen Editor für MAML?
- und was hat das mit VSX zu tun?
Antworten:
- Ich suche nach einem solchen Editor, weil ich damit meine Dokumentation für meinen Sourcecode erstellen will. Das will ich deshalb in diesem Format tun, weil Sandcastle diese Dateien verarbeiten kann und daraus zu meiner Referenzdokumentation auch noch zusätzliche Informationen in einem klar strukturierten Markup erstellen kann. Das sieht nicht nur sehr schön aus, sonder lässt sich dann auch wunderbar automatisieren.
- Nachdem ich auf dem Markt (OpenSource und kommerziell) nichts gefunden habe, hatte ich mich drauf und dran gemacht Informationen zu sammeln, wie ich so etwas ins Visual Studio integrieren kann. Ich als Entwickler will ja nach Möglichkeit alles aus einer Hand haben. Was liegt also näher. (SHFB und DocProject werden mit dem nächsten Release entsprechende visuelle Unterstützung anbieten)
Ob sich nun daraus ein Projekt entwickelt oder nicht, mich hatte die Sucharbeit neugierig gemacht. Nun musste meine Entdeckernatur unbedingt wissen, wie so ein VSPackage mit einem eigenen XmlEditor zu erstellen ist. Das erste was ich fand war der Hinweis auf selbigen Namespace Microsoft.VisualStudio.XmlEditor. Dokumentation dazu habe ich keine gefunden; lediglich einen Artikel von Chris Lovett aus dem code-magazine. Hier stellt er ganz kurz und knapp vor, wie die neue Xml-API aussieht. Also gut, dachte ich mir und erstellte ein erstes VSPackage.Dann wollte ich eine Referenz dazu hinzufügen ... AddReferenz-> GAC. Aber nichts dergleichen. Kein Microsoft.VisualStudio.XmlEditor. Über die Windowssuche habe ich mir dann die Dll herausgesucht, den Pfad kopiert und dann die Referenz über den Suchen-Reiter hinzugefügt. Danach fing ich an, den vorliegenden Code zu analysieren. Irgendwann dachte ich mir dann. So kann das nicht angehen, das ist mir alles zu experimentell. Ich will etwas mehr dokumentierte Lektüre, oder Erfahrungsberichte. Und um das alles kurz zu halten, hier die Referenzen und ein kleines HowTo was alles notwendig ist, um mit VSX als völliger Neuling anzufangen:
- VS2008 SDK herunter laden und installieren
- LearnVSXNow! von Istvan Novak ist eine sehr gelungene und gute Einführung in die Welt der Visual Studio Shell und der Erweiterung selbiger. Er ist auch Author von LinqOverC#, einem Linqprovider für ein Codemodel im Visual Studio.
- Als sehr kompetente Quelle hat mir auch Pablo Galiano mit seinen Antworten im Microsoft Forum für VSX und seinem Blog geholfen. Er arbeitet bei Clarius Consulting und ist auf codeplex für Projekte wie das IronPyhtonStudio oder auch den StoryboardDesigner verantwortlich. Eine Übersicht der Projekte findet sich hier. Auf der code-Plattform findet man von ihm die PowerCommands for VS2008 oder LinqToCodeModel.
- Dem nicht genug, hat er auch noch ein weiteres Projekt gehostet. VSSDK Assist heißt es und ist eine Guidance Package Extension. Was das ist? Ein Automationsinterface für die VS IDE. Alles notwendige findet sich in den Prerequisist wieder.
Das sind genug Quellen und Informationen um sich erst einmal gute zwei Wochen damit zu beschäftigen. Viel Spaß damit. Wer Fragen dazu hat kann sich gerne bei mir melden.
Kleine Anwendungen und das richtige Datenbank-System
02.06.2008 08:00:49
|
Norbert Eder
Auch kleine Anwendungen müssen in vielen Fällen Daten halten und diese auch wieder bereit stellen. Nun stellen sich oft die Frage, welches Datenbank-System denn eigentlich das richtige sei.
Ich selbst bin ja ein Freund von XML, aber eben nicht immer, wenn es darum geht, Daten zu speichern. Vor allem dann nicht, wenn die Datenstrukturen komplexer werden (das muss nicht unbedingt mit einer hohen Anzahl an Daten einher gehen). D.h. für wenige und einfache Daten kann ruhig eine XML-Datei verwendet werden.
Wird es komplexer, greifen immer noch viele zu Access. Hier bin ich eher dagegen. Es ist zwar ein nettes Tool, wenn mal eben schnell im Sekretariat eine kleine Adressverwaltung (eventuell Outlook übersehen?) erstellt werden muss, oder eine andere kleine Anwendung. Für das Speichern von Daten aus einer Anwendung heraus würde ich es nicht wirklich empfehlen, da es dann doch vorkommen kann, dass man eben mal schnell die Reparatur-Funktion anwerfen muss (das muss auch nicht immer funktionieren). Zudem ist es mir ein wenig zu behäbig. Hier bieten sich meiner Meinung nach zwei Möglichkeiten an (wenn man sich auf die Microsoft-Welt beschränkt):
- SQL Server Express Edition
- SQL Server Compact Edition
Ein SQL Server Express Edition muss am System installiert werden und fungiert als echter Datenbank-Server. Ideal dann, wenn eine Multi-User-Anwendung entwickelt wird, die dennoch ein geringes Datenaufkommen bereitet (wenn auch die Express Edition äußerst performant ist).
Spricht die Anwendung einen kleineren Userkreis an, also überhaupt nur einen einzigen Benutzer, dann wäre der SQL Server Compact Edition definitiv eine Möglichkeit. Klein, handlich und lediglich eine Referenz auf eine Assembly, als auch nur eine Datendatei. Zugriff erfolgt über einen eigenen Provider, SQL natürlich inklusive. Eine wirkliche Alternative, keine notwendige Installation und noch dazu recht speedy.
Wer mit der SQL Server Compact Edition noch nichts gemacht hat, sie aber in einem Projekt einsetzen möchte, der sei auf die folgenden beiden Links verwiesen, welche mit Erklärungen und Sourcecode für C# und VB.NET aufzeigen, wie diese Edition verwendet wird:
Getting Started with SQL Server Compact Edition
SQL Server Compact Edition with C# and VB.NET
Panorama-Fotospielereien mit Windows Live Fotogalerie
01.06.2008 22:52:00
|
Steffen Ritter
Vergangenes Wochenende war ich auf Oliver Gassners Barcamp Bodensee. Als gebürtiger Lindauer musste ich natürlich die Chance nutzen und auch auf der Lindauer Insel vorbeischauen. Wegen des guten Wetters ließ ich mich dazu verleiten, mit dem Telefon ein paar Schnappschüsse vom Seehafen zu machen. Eigentlich hatte ich vor, diese später in Photoshop Elements zu einem Seehafen-Panorama zusammenzusetzen. Das Ergebnis meiner Bemühungen mit meinem viel geliebten und erprobten Photoshop Elements 5 war leider nicht sehr befriedigend:

Offensichtliche Brüche und Doppelungen verzerren das Bild – und was soll diese große weiße Fläche, wenn doch theoretisch ein nahtloser Anschluss möglich ist?
Ich war kurz davor, mir eine Trial-Version der neuen Elements 6er herunter zu laden oder gleich ein Update zu kaufen, als mich gerade noch rechtzeitig ein Kollege auf unser eigenes Tool hinwies: Das kostenlose Windows Live Fotogalerie mit integrierter Panorama-Funktion.
Bei exakt demselben Ausgangsmaterial montiert Windows Live Fotogalerie ein nahezu perfektes Panorama (für die Helligkeitsunterschiede nehme ich die Schuld auf mich):

Ich muss eingestehen: Ich bin von Windows Live Fotogalerie begeistert.
Für den Foto-Workflow und Digital Asset Management ist natürlich Expression Media – der Nachfolger von iView MediaPro – mein Tool der Wahl, aber für Panoramabilder kenne ich derzeit kein besseres Tools als Windows Live Fotogalerie.
Besagter Kollege aus der Windows Live-Abteilung hat mich außerdem darauf hingewiesen, dass derzeit ein deutschlandweiter Wettbewerb läuft, bei dem die besten mit Windows Live Fotogalerie erzeugten Panoramafotos prämiert werden. Alle Infos und Teilnahmebedingungen hier: http://pressecenter.msn.de/377_WL_Photo_Europe.OSG
PS: Und um diesen Beitrag nicht vollkommen Silverlight-frei enden zu lassen: Ich werde jetzt umgehend versuchen, aus diesem oder einem anderen etwas größeren Panorama eine schnieke Deep Zoom-Anwendung zu machen :)
Links aus diesem Beitrag: