.
Anmeldung | Registrieren | Hilfe

.NET-Blogs Archiv April 2008

"WHERE IN" - Abfrage mit LINQ to SQL

30.04.2008 14:30:00 | Jürgen Gutsch

Nach etwas probieren hatte ich dann heraus, wie ich mit LINQ to SQL einen "WHERE IN" - Abfrage bekommen:

List<string> tmpList = new List<string>();
foreach (Group group in user.Groups)
  tmpList.Add(Group.ShortName);
string[] tmpArr = tmpList.ToArray<string>();

var calendars = from cal in db.Calendars
                      where (tmpArr.Contains(cal.OWNER))
                      select cal;

Die Contains-Abfrage in der WHERE Bedingung erzeugt eine "WHERE IN"- Abfrage in dem Stil

([t0].[OWNER] IN (@p1, @p2, @p3, @p4))

Ganz einfach...
Man muss es nur wissen...
Bzw. jemand sollte es mal dokumentiert haben ;-)

"WHERE IN" - Abfrage mit LINQ to SQL

30.04.2008 14:30:00 | Jürgen Gutsch

Nach etwas probieren hatte ich dann heraus, wie ich mit LINQ to SQL einen "WHERE IN" - Abfrage bekommen:

List<string> tmpList = new List<string>();
foreach (Group group in user.Groups)
  tmpList.Add(Group.ShortName);
string[] tmpArr = tmpList.ToArray<string>();

var calendars = from cal in db.Calendars
                      where (tmpArr.Contains(cal.OWNER))
                      select cal;

Die Contains-Abfrage in der WHERE Bedingung erzeugt eine "WHERE IN"- Abfrage in dem Stil

([t0].[OWNER] IN (@p1, @p2, @p3, @p4))

Ganz einfach...
Man muss es nur wissen...
Bzw. jemand sollte es mal dokumentiert haben ;-)

UI Automatisierung in Team Build integrieren

30.04.2008 13:53:15 | Christian Binder

Im Webcast UI Automation Framework haben wir prinzipiel aufgezeigt, wie man ein UITest für eine Winforms Anwendung mit Hilfe des UI Automation Frameworks erstellen kann und wie diese in einen UnitTest integriert werden können.

Im folgendem möchte ich aufzeigen wie man einen solchen UI-UnitTest in Team Build integrieren kann.
Was ist zu tun?

UITest benötigen eine "Interactive Session", wir müssen also einen Interactive Build Agent definieren und den Build Service entsprechend für einen Interactive Port konfigurieren. Die notwendigen Schritte sind unter folgendem Link beschrieben.  

Danach kann man den Build Agent konfigurieren (mit dem Interactive Port):

image

 

Bevor man Builds mit diesem Agent ausführen kann, muss der Interactive Build Service auf dem
BuildServer gestartet werden. Für UI-Tests ist es erforderlich, dass ein Account angemeldet ist
und in diesem Kontext der Interactive BuildService gestartet wurde. Ich habe dies mit einem
Batch automatisiert:

StartInteractiveBuildService.bat

runas /user:TFSBUILD /savecred "cmd /k \"C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\TFSbuildservice.exe\""

image

 

Nun kann eine Build Definition erstellt werden, welche den BuildAgent verwendet.


Eine Hürde gilt es aber noch zu nehmen, für die es aber je nach Anforderung unterschiedliche Lösungsansätze gibt.
Der Unit-Test muss das UI automatisch starten/schliessen. Im Prinzip sehr einfach, allerdings liegt das im Build erzeugte UI-image in Abhängigkeit von verschiedenen Parametern in unterschiedlichen Pfaden. Die Abhängigkeiten sind z.B. Desktop Build oder Team Build, Debug Build oder Release Build,. In allen Fällen ergibt sich ein anderer Pfad zum Image.

Beispiel:

Desktop Build: "BasePath\Calc\bin\Debug\calc.exe"
Team Build: "BasePath\Binaries\Debug\calc.exe"  

wobei der BasePath auch unterschiedlich ist, aber im Test Kontext verfügbar ist.

Ich habe mir für dieses Beispiel ein Anforderungsrahmen gegeben:
- keine Änderung der Default Build-Pfade
- der UnitTest soll das Image immer Starten/Beenden, ob DesktopBuild oder TeamBuild
- es wird Debug- und Release Build-Konfiguration unterstützt


Nun zu den Details.
Die Demo Solution enthält 3 Projekte:
- Calc (das UI-Image, welches getestet werden soll)
- UIDriverLib (Wrapper für das UI-Automation Framework, ich empfehle den  White Wrapper zu verwenden)
- UIDruverLibTests(enthält die Unit-tests)

Der Fokus liegt auf der TestClass im UIDruverLibTests, welche 2 UnitTests enthält. Test1 ist ein nativer UI Test, der keinen Wrapper verwendet. Test2 verwendet den Wrapper. Details hierzu finden Sie im Webcast.

Um die oben beschriebene Hürde zu nehmen, habe ich die Logik zum Starten in die Region InitHelper gepackt. Das Beenden des Images muss im [TestCleanup()] durchgeführt werden, um sicherzustellen, dass keine UI's auf dem BuildServer verbleiben.
 

image 

Die InitHelper Region enthält mehrere Helper Methods. Im Unit-Test verwende ich nur InitUIImage(). um das Image zu starten, die anderen Methoden sind Helper für InitUIImage().

image

Da ich im UnitTest einige Parameter benötige, um den  Pfad für das UIImage zu erstellen, habe ich mich entschieden die wichtigsten Parameter nicht direkt im Test als Konstanten zu definieren, sondern diese als zusätzliche Test-Properties abzulegen und somit im UI zugänglich zu machen:

image

Mit GetCustomProperties lese ich diese Properties dann aus. GetImagePath enthält dann die Logik den Pfad in Abhängigkeit aller Parameter zu erstellen. StartUIImage startet dann das Image.

Auf diese Weise kann ich den UI Unit-Test auf dem Desktop oder als TeamBuild, als Release oder Debug ausführen.

Das Beispiel ist reiner Demo code, was man auch an den Sleep's sieht (sonst gehts einfach zu schell). Dennoch hoffe ich, die ein oder andere Idee gegeben zu haben, UI-Automation als Teil des Build Prozesses zu implementieren. In Prodcution das entsprechende Exception Handling nicht vergessen!

 

Ausblick:  Coded UI-tests sind schon jetzt im aktuellen Rosario CTP 12 enhalten :-)

image

Mit der Option den code aus einem Recording erstellen zu lassen:

image

Viel Spass

Chris

Visual Studio 2008 Gewinnspiel auf ASP.NET Zone

29.04.2008 16:08:00 | Peter Bucher

Auf der ASP.NET Zone gibt es aktuell ein Gewinnspiel, dabei können 3 Visual Studio Lizenzen abgestaubt werden.

Ich zitiere:

Wir freuen uns, euch in Zusammenarbeit mit Microsoft ein attraktives Gewinnspiel rund um Visual Studio 2008 anbieten zu können.

Zu gewinnen gibt es insgesamt drei Visual Studio 2008 Lizenzen *, jeder der Gewinner erhält:

  • 1 * Visual Studio 2008 Standard Edition
  • 1 * Visual Studio Team System 2008 Team Foundation Server
  • 1 * msdn Library

* Bitte beachtet: Die Gewinne werden von Microsoft zur Verfügung gestellt und sind selbstverständlich Vollversionen.
Die Lizenzen sind sogenannte NFR (Not for Resale) Lizenzen, welche nicht für den Wiederverkauf bestimmt sind und
daher nicht verkauft werden dürfen.

Weitere Informationen zum Gewinnspiel sowie zu den Teilnahmebedingungen im folgenden Link:

Ausblick auf TFS 2008 SP1

29.04.2008 09:15:00 | Jürgen Gutsch

Brian Harry hat einen interessanten Ausblick auf das Service Pack 1 des TFS 2008 veröffentlicht:
Team Foundation Server 2008 SP1 Preview

Mein Buch "LINQ" ist da

25.04.2008 20:39:00 | Ozgur Aytekin

Es ist soweit. Mein Buch "LINQ" ist da.

Das Buch vermittelt einen ersten Überblick über das Thema LINQ. Theoretische Einführungen in die einzelnen Themengebiete werden duch praktische Beispiele und eine LINQ-Referenz ergänzt, damit Sie Ihre ersten LINQ-Abfragen implementieren und leicht nachvollziehen können.

 

Aus dem Inhalt:

- Einführung in das Thema LINQ

- Vorstellung der wichtigsten Elemente und Tools für den Einsatz von LINQ to SQL

- Schritt-für-Schritt-Anleitung zum Erstellen einer Anwendung mit LINQ to SQL

- Referenzkapitel zu den einzelnen Query-Operatoren mit Beispielen

- Informationen über das Thema LINQ to Objects

- LINQ to XML und Umgang mit XML-Daten

- LINQ to DataSet Funktionalitäten und Datenbindung

 

Angaben zu meinem Buch:

Addison-Wesley - LINQ - Theorie und Praxis für Einsteiger

Broschiert: 288 Seiten
Verlag: Addison-Wesley, München; Auflage: 1 (18. April 2008)
Sprache: Deutsch
ISBN-10: 3827326168
ISBN-13: 978-3827326164

 

Im Buch findet Ihr meine E-Mail-Adresse. Wenn Ihr zum Thema LINQ Fragen habt, könnt Ihr diese direkt an meine E-Mail-Adresse schicken. Ich werde es versuchen, Eure Fragen zu beantworten.

 

Viel Spass beim Lesen...

Özgür Aytekin

LINQ to SQL - Transaction Beispiel

24.04.2008 20:51:00 | Ozgur Aytekin

Als Transaktion (von lat. trans „über“, actio zu agere „(durch)führen“) bezeichnet man in der Informatik eine feste Folge von Operationen, welche als eine logische Einheit betrachtet werden. Transaktionen werden von Transaktionssystemen verarbeitet; diese erzeugen dabei aus mehreren Transaktionen eine Historie. Meist kommen sie bei Datenbanken zum Einsatz.

Quelle: Wikipedia.de

In LINQ wird eine Transaktion automatisch gestartet, wenn die SubmitChanges-Methode der DataContext-Klasse aufgerufen wird. Dabei verwendet LINQ to SQL eine explizite Transaktion.

Eine manuelle Kontrolle über die Transaktion kann durch Erstellung ein eigenes Transaction-Objekt übernommen werden.

Für den folgenden lauffähigen Beispielcode wird die AdventureWorks-Datenbank verwendet. Eine LINQ to SQL Classes-Datei (dbml-Datei) mit dem Namen AdventureWorks.dbml und mit einer Entity-Klasse



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 using System;
2
3 namespace LinqTransactionSample0001
4 {
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 // DataContext Objekt erstellen
10 AdventureWorksDataContext db = new AdventureWorksDataContext();
11
12 // Transaction Objekt erstellen und mit NULL initialisieren
13 System.Data.Common.DbTransaction trans = null;
14
15 // Datenbankverbindung öffnen und den aktiven Transaction der Verbindung
16 // an das trans Objekt übergeben
17 db.Connection.Open();
18 trans = db.Connection.BeginTransaction();
19
20 // DataContext Objekt wird ab hier das trans Objekt für die Transaktionen verwenden
21 db.Transaction = trans;
22
23 // Zwei neue CountryRegion Objekte erstellen
24 CountryRegion cr1 = new CountryRegion();
25 cr1.Name = "Country ABC";
26 cr1.CountryRegionCode = "ABC";
27 cr1.ModifiedDate = DateTime.Now;
28
29 CountryRegion cr2 = new CountryRegion();
30 cr2.Name = "Country DEF";
31 cr2.CountryRegionCode = "DEF";
32 cr2.ModifiedDate = DateTime.Now;
33
34 // CountryRegion Objekt an die CountryRegions Collection hinzufügen
35 db.CountryRegions.InsertOnSubmit(cr1);
36 db.CountryRegions.InsertOnSubmit(cr2);
37
38 try
39 {
40 db.SubmitChanges();
41
42 // Wenn bis hier keinen Fehler auftritt, wird die Commit-Method des Transaction-Objekts aufgrufen
43 // und die Daten werden in die Datenbank geschrieben.
44 // Commit transaction
45 trans.Commit();
46 }
47 catch(Exception ex)
48 {
49 // Bei einem Fehler-Fall wird die Rollback-Methode des Transaction-Objektes aufgerufen
50 // Rollback transaction
51 if ( trans != null)
52 {
53 trans.Rollback();
54 }
55
56 Console.WriteLine(ex.Message.ToString());
57 }
58 finally
59 {
60 // Die Datenbank-Verbindung schliessen, wenn die Verbidung offen ist.
61 // Close the connection
62 if(db.Connection.State == System.Data.ConnectionState.Open)
63 {
64 db.Connection.Close();
65 }
66 }
67
68 Console.ReadKey();
69 }
70 }
71 }
72


Das Beispiel-Projekt findet Ihr unter: LinqTransactionSample0001

CodeSnippet: XmlReader aus XML String erstellen

24.04.2008 10:14:00 | Jürgen Gutsch

Eine Zeile Code, die ich immer wieder neu im Netz suchen muss:

XmlReader reader = XmlReader.Create(new StringReader(xml));

Damit erstelle ich einen XmlReader aus einem String welcher XML Daten enthält.

Die meisten Beispiele im Netz (selbst in der MSDN) zeigen leider nur, wie man ein XML Reader mit einer Datei oder einer externen Ressource erstellt:
z. B: Erstellen von XML-Readern

Damit ich nicht jedesmal neu suchen muss, schreibe ich es jetzt in mein Blog. (Jetzt muss ich mir nur noch merken, dass ich die Zeile hier veröffentlicht habe...)

Visual Studio 2008 and .NET Framework 3.5 Training Kit

24.04.2008 07:58:00 | Ozgur Aytekin

Microsoft bietet ein Training-Kit für Visual Studio 2008 und .NET Framework 3.5.

Dieses Training-Kit beinhaltet unter anderem:

- Presentationen

- Hands-On-Labs

Die Themen sind folgende Features und Technologien:

- LINQ

- C# 3.0

- Visual Basic 9

- WCF

- WF

- WPF

- ASP.NET AJAX

- VSTO

- CardSpace

- SilverLight

- Mobile and Application Lifecycle Management

Es lohnt sich jedenfalls dieses Training-Kit herunterzuladen und anzuschauen.

Unter folgende URL könnt Ihr die Installations-Datei herunterladen:

Visual Studio 2008 and .NET Framework 3.5 Training Kit

Virtual TechDays

23.04.2008 19:13:00 | Ozgur Aytekin

Das Info-Material (Recorded Sessions and Presentations) für Virtual TechDays vom 9. und 10. April 2008 kann unter folgende URL heruntergeladen werden:

http://www.microsoft.com/india/virtualtechdays/

Die Themen waren:

Windows Server 2008

SQL Server 2008 - Business Intelligence and Admin

SQL Server 2008-RDBMS

Visual Studio  2008 Fundamentals

SQL Server 2008 High Availability & Security

Visual Studio 2008 Web Applications

Visual Studio 2008 Smart Clients

Eine einfache Bildergalerie mit ASP.NET

23.04.2008 12:11:00 | Jürgen Gutsch

Für ein kleineres Projekt benötigte ich eine einfache Bildergalerie die ich hiermit kurz vorstellen möchte

Folgende Techniken werden genutzt:

Die Bilder sollen aus einem Verzeichnis innerhalb des Webs ausgelesen und dargestellt werden. Wie die Bilder dorthin gelangen, ist erst mal nicht wichtig. Hierfür habe lese ich mit Hilfe der DirectoryInfo die enthaltenen Dateien aus, schreibe die Eigenschaften der einzelnen FileInfos in eine eigene Hilfsklasse und füge diese Klassen einer generischen Liste hinzu:

private IList<ImageFile> getData()
{
  DirectoryInfo di = new DirectoryInfo(   
      Server.MapPath("~/Images/Gallery/"));
  IList<ImageFile> files = new List<ImageFile>();
  foreach (FileInfo file in di.GetFiles())
    files.Add(new ImageFile()
      {
        FileName = file.Name,
        FullName = file.FullName,
        FileSize = file.Length,
        CreateDate = file.CreationTime,
        WriteTime = file.LastWriteTime,
        AccessTime = file.LastAccessTime
    });
  return files;
}

Die Hilfsklasse sieht so aus:

public class ImageFile
{
    public string FileName { get; set; }
    public string FullName { get; set; }
    public long FileSize { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime WriteTime { get; set; }
    public DateTime AccessTime { get; set; }
    public string GetImageLink(int width, int height)
    {
        string link = "~/ShowImage.ashx?filename=" +
            this.FileName;
        if (width > 0)
            link += "&width=" + width.ToString();
        if (height > 0)
            link += "&height=" + height.ToString();
        return link;
    }
}

Die kleine Methode GetImageLink benötige ich nachher im ListView. Sie setzt mir die URL zum generischen Handler mit allen nötigen Parametern zusammen.

Das binden der Liste an das ListView findet im PreRender Event Handler der ListView statt, denn ein Binding im Page_Load führt dazu, das die gewählte Seite erst nach dem zweiten PostBack angezeigt wird:

protected void GalleryListViewPager_PreRender( object sender, EventArgs e)
{
  this.GalleryListView.DataSource = getData();
  this.GalleryListView.DataBind();
}

Für die ListView benötige ich ein ItemTemplate und ein LayoutTamplate.

<asp:ListView ID="GalleryListView" runat="server">
    <LayoutTemplate>
    </LayoutTemplate>
    <ItemTemplate>
    </ItemTemplate>
</asp:ListView>

Das LayoutTemplate enthält die Definition des Containers welches anschließend die Items enthalten soll. Es könnte also die Definition eines TABLE Controls enthalten, oder in meinem Fall eine ungeordnete Liste mit der CSS Klasse "imagelist":

<ul class="imagelist">
    <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</ul>

Das ListView platziert den Inhalt des ItemTemplates in den angegebenen PlaceHolder hinein. Die ID des Placeholder muss "itemPlaceholder" lauten.

Der Inhalt des ItemTemplates sieht wie folgt aus:

<li>
    <asp:HyperLink ID="link" runat="server" NavigateUrl='<%# (Container.DataItem as
        GO.WebGallery.ImageFile).GetImageLink(600, 0) %>'
rel="lightbox[gallery]"
        ToolTip='<%# (Container.DataItem as GO.WebGallery.ImageFile).FileName %>'>
        <asp:Image ID="image" runat="server" Width="80px" Height="80px"
            BorderWidth="1px" ImageUrl='<%# (Container.DataItem as 
            GO.WebGallery.ImageFile).GetImageLink(80, 80) %>'
AlternateText="" />
    </asp:HyperLink>
</li>

Wieso eine ungeordnete Liste? Weil eine Bildergalerie nichts anderes ist als eine Liste mit Bildern...

Beim DataBinding mit Objekten liegt aus meiner Sicht ein weiterer klarer Vorteil darin, dass ich hier direkt mit den Objekten arbeiten kann. "Container.DataItem" ist Praktisch eines meiner gebundenen Objekte. Ein Cast ("Container.DataItem as GO.WebGallery.ImageFile") und ich kann bequem auf die Eigenschaften des Objekts zugreifen.

Das Paging übernimmt hier das DataPager Control, welches ich unterhalb der ListView Platziert habe

<asp:DataPager ID="GalleryListViewPager" runat="server"
        PagedControlID="GalleryListView" PageSize="12"
        OnPreRender="GalleryListViewPager_PreRender">
    <Fields>
        <asp:NextPreviousPagerField FirstPageText="&lt;&lt;"
                ShowFirstPageButton="True" ShowNextPageButton="False"
                PreviousPageText="&lt;" />
        <asp:NumericPagerField />
        <asp:NextPreviousPagerField LastPageText="&gt;&gt;"
                ShowLastPageButton="True" ShowPreviousPageButton="False"
                NextPageText="&gt;" />
    </Fields>
</asp:DataPager>

Die letzte Komponente die ich hier kurz beschreiben möchte, ist der generische HttpHandler. Aufgerufen mit der URL ("~/ShowImage.ashx?filename=100_2116.JPG&width=80&height=80") liefert er das entsprechende Bild in der angegebenen Größe.

Zuerst wird geprüft, ob es von dem angegebenen Bild bereits ein generiertes Thumbnail gibt, wenn nicht wird das Bild in ein Bitmap Objekt geladen und bearbeitet. Mit Hilfe einiger Hilfsmethoden aus dem sharpcms (im Projekt in der Klasse "Tools") werden die Bilder verkleinert und geschärft um anschließend im HttpHandler im Ordner "Thumbs" abgelegt zu werden.

Die Ausgabe des Bildes an den ResponseStream erfolgt mit folgenden Zeilen:

context.Response.ContentType = "image/jpeg";
if (System.IO.File.Exists(thumbPath))
  context.Response.TransmitFile(thumbPath);
else
  context.Response.TransmitFile(filePath);

Das Projekt kann hier heruntergeladen werden:
WebGallery.zip (ca. 1MB)

Private Anfragen zu Problemen und wieso ich diese nicht beantworte

22.04.2008 11:40:00 | Peter Bucher

Ab und an bekomme ich über das Kontaktformular in meinem Blog, meiner Webseite oder aber per Private Message in Foren Private Anfragen zu Technischen Problemen.
Ich rege mich bei solchen Anfragen nicht auf, sondern verweise freundlich auf Online Foren in denen ich aktiv bin.

Das hat auch mehrere, plausible Gründe:

  • Wenn die Frage in einem Forum gestellt wird, haben andere auch etwas von der Antwort
  • In einem Forum sind im Normalfall mehrere Leute unterwegs
  • Das ergibt - abgsehen davon, das die anderen Leute in verschiedensten Bereichen auch mehr Ahnung haben können als ich - auch mehrere Meinungen zu einem Problem
  • Auch geschieht die gesamte Hilfeleistung auf kostenloser und freiwilliger Basis

Wenn jemand allerdings Privatsupport von mir wünscht, kann ich das gerne arrangieren, aber das würde natürlich etwas kosten.
Ich denke das geht anderen auch so und dieses Statement kann als Allgemein angesehen werden.

Kommentare erwünscht!

CSS: 100% Höhe bei DIVs

21.04.2008 21:39:00 | Jürgen Gutsch

Hin und wieder kommt es vor, dass DIV Elemente 100% hoch sein müssen.

Wozu benötigt man 100% hohe DIV Elemente? Oftmals werden Websites so gestaltet, dass sie 100% der Höhe des Browserfensters ausnutzen sollen. In den Zeiten von AJAX und Web 2.0 sollen immer öfter DHTML Fensterchen aufgehen und der Rest der Seite ausgegraut werden.

Wenn man beachtet, wie eine HTML Seite aufgebaut ist, ist es eigentlich recht einfach.

Gegeben ist folgendes HTML:



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Untitled Page</title>
    <link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1">
        <div id="page">
        </div>
    </form>
</body>
</html>

Das Element
mit der ID "page" soll 100% der Seitenhöhe nutzen und 48.7em (das entspricht mit normalen Einstellungen ca 780px) breit sein. Damit das Element auf der weißen Seite sichtbar wird, so es temporär rot eingefärbt werden.

normalerweise würde man jetzt hingehen und folgende Formatierung für die ID "page" in die CSS Datei schreiben:

#page
{
    height: 100%;
    width: 48.7em;
    background-color: red;
}

Damit es keine Ränder gibt wird man den BODY und das FORM ebenfalls formatieren:

body, form
{
    margin: 0px;
    padding: 0px;
}

Mit dem Resultat, das unser DIV jetzt genau eine Zeile hoch, rot und 48.7em breit ist, obwohl 100% angegeben ist.

Bis hier hin werden alle schon gekommen sein... ;-)

100% ist eine relative Angabe. Wir müssen uns also Fragen: "100% von was?"
Vom Fenster, klar. Aber woher weis das CSS wie hoch das Fenster ist? Gar nicht!

CSS formatiert Elemente, relativ zum vorhergehenden, oder relativ zum übergeordneten. So werden Positionierung in den meisten Fällen relativ zum vorherigen Element vorgenommen. Und das meiste andere, relativ zum übergeordneten.

Was heißt das? Das heißt, dass das DIV jetzt 100% die Höhe des vorhergehenden Elements hat, bzw. die Höhe des Whitespace Zeichens innerhalb des DIVs

Was tun? Die Lösung liegt auf der Hand. Wir müsse die Elemente HTML, BODY, und FORM ebenfalls auf 100% Höhe setzen:

html, body, form
{
    height: 100%;
    margin: 0px;
    padding: 0px;
}
#page
{
    height: 100%;
    width: 48.7em;
    background-color: red;
}

HTML als oberstes Element, ist damit genau so hoch wie die Frame des Browserfensters und die untergeordneten Elemente BODY und FORM sind genauso hoch wie das jeweilige übergeordnete.

Im IE7 muss der FORM Tag fälschlicherweise nicht berücksichtigt werden. Es würde also reichen nur HTML und BODY 100% groß zu machen. Firefox und Opera benötigen dagegen ein 100% hohes FORM Tag.

MERGE-Statement in Microsoft SQL Server 2008

20.04.2008 19:19:00 | Ozgur Aytekin

Mit Hilfe des MERGE-Statements können die Daten aus der Quelle in die Ziel-Tabelle unter bestimmten Bedingungen transferiert werden.

Das MERGE-Statement in Microsoft SQL Server 2008 kann in die Ziel-Tabelle neuen Datensätze hinzufügen oder die bestehenden Datensätze aktualisieren. Dabei können Kriterien definiert werden, unter welche Bedingung ein Datensatz in der Ziel-Tabelle aktualisiert oder hinzugefügt werden soll. Die Löschung einen Datensatz in der Ziel-Tabelle kann ebenfalls mit Hilfe des MERGE-Statements implementiert werden.

Der folgende Beispiel-Code erstellt in der Datenbank zwei neue Datenbanktabellen mit dem Namen Country1 (C1) und Country2 (C2). Die Tabelle C1 wird als Ziel und C2 wird als Quelle in dem Beispiel verwendet. In der C1 werden drei neue Einträge und in der C2 werden vier neue Einträge erstellt.

-- Erstellen Ziel-Tabelle in einer SQL Server Datenbank
CREATE TABLE [dbo].[Country1](
[ID] [int] NOT NULL,
[Country] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)

-- Erstellen drei neue Datensätze in der Datenbanktabelle Country1 (Ziel)
INSERT INTO [dbo].[Country1] ([ID], [Country])
SELECT 1, 'SWITZERLAND' UNION ALL
SELECT 2, 'GERMANY' UNION ALL
SELECT 3, 'AUSTRIA'


-- Erstellen Quelle-Tabelle in einer SQL Server Datenbank
CREATE TABLE [dbo].[Country2](
[ID] [int] NOT NULL,
[Country] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)


-- Erstellen vier Datensätze in der Datenbanktabelle Country2 (Quelle)
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (1, 'SWITZERLAND')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (2, 'DEUTSCHLAND')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (4, 'TURKIYE')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (5, 'ITALY')


 



Für den INSERT darf die ID der C2-Tabelle in der C1-Tabelle nicht vorkommen (TARGET NOT MATCHED THEN):



MERGE [Country1] AS C1
USING [Country2] AS C2
ON C1.ID = C2.ID

-- Wenn, ID der C2 in der Tabelle C1 nicht vorhanden ist,
-- dann wird der Datensatz in der C1 erstellt (INSERT)
WHEN TARGET NOT MATCHED THEN
INSERT (ID, Country)
VALUES (C2.ID, C2.Country)


Und für den UPDATE muss die ID der C1-Tabelle in der C2-Tabelle vorhanden sein (MATCHED AND C1.ID = C2.ID):



-- Wenn, ID der C2 in der Tabelle C1 vorhanden ist,
-- dann wird der Datenatz in der C1 aktualisert (UPDATE)
WHEN MATCHED AND C1.ID = C2.ID THEN
UPDATE SET Country = C2.Country;


 



Der ganze Beispielcode ist unten aufgelistet:



--BEGIN TRANSACTION

-- Wenn die Datenbanktabelle Country1 (Ziel) oder Country2 (Quelle) in der Datenbank bereits exisitiert,
-- werden sie zuerst gelöscht.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Country1]') AND type in (N'U'))
DROP TABLE [dbo].[Country1]
GO

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Country2]') AND type in (N'U'))
DROP TABLE [dbo].[Country2]
GO


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- Erstellen Ziel-Tabelle in einer SQL Server Datenbank
CREATE TABLE [dbo].[Country1](
[ID] [int] NOT NULL,
[Country] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)



-- Erstellen drei neue Datensätze in der Datenbanktabelle Country1 (Ziel)
INSERT INTO [dbo].[Country1] ([ID], [Country])
SELECT 1, 'SWITZERLAND' UNION ALL
SELECT 2, 'GERMANY' UNION ALL
SELECT 3, 'AUSTRIA'



-- Erstellen Quelle-Tabelle in einer SQL Server Datenbank
CREATE TABLE [dbo].[Country2](
[ID] [int] NOT NULL,
[Country] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)




-- Erstellen vier Datensätze in der Datenbanktabelle Country2 (Quelle)
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (1, 'SWITZERLAND')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (2, 'DEUTSCHLAND')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (4, 'TURKIYE')
INSERT INTO [dbo].[Country2] ([ID],[Country]) VALUES (5, 'ITALY')


-- Ausgeben Inhalte der beiden Tabellen
SELECT * FROM Country1
SELECT * FROM Country2


               
-- Verwendung MERGE-Statement
MERGE [Country1] AS C1
USING [Country2] AS C2
ON C1.ID = C2.ID

-- Wenn, ID der C2 in der Tabelle C1 nicht vorhanden ist,
-- dann wird der Datensatz in der C1 erstellt (INSERT)
WHEN TARGET NOT MATCHED THEN
INSERT (ID, Country)
VALUES (C2.ID, C2.Country)

-- Wenn, ID der C2 in der Tabelle C1 vorhanden ist,
-- dann wird der Datenatz in der C1 aktualisert (UPDATE)
WHEN MATCHED AND C1.ID = C2.ID THEN
UPDATE SET Country = C2.Country;


-- Ausgeben Inhalte der beiden Tabellen
SELECT * FROM Country1
SELECT * FROM Country2

--ROLLBACK TRANSACTION


Wenn die Daten der Tabelle C1 vor und nach Verwendung des MERGE-Statements verglichen werden, sehen die Daten wie folgt aus:

MERGESample



Bemerkung: Die Verwendung von BEGIN und ROLLBACK-Transaction haben keinen Einfluss auf das Beispiel. Ich wollte nur meine Datenbank sauber halten :-)

MSDN Magazine April 2008

20.04.2008 18:32:00 | Ozgur Aytekin

MSDN Magazine April 2008 könnt Ihr unter http://msdn2.microsoft.com/en-us/magazine/cc501178.aspx herunterladen.

Unter der Kolumne Test Run findet Ihr ein interessantes Artikel über LINQ.

Test Run: Testing SQL Stored Procedures Using LINQ

Language Integrated Query makes lots of things easier. Here we put LINQ, or more specifically the LINQ to SQL provider, to use testing SQL stored procedures. Dr. James McCaffrey

Viel Spaß beim Lesen

WPF Performance Suite Download Location

19.04.2008 12:26:00 | Klaus Bock

Wer WPF als UI verwendet der wird die WPF Performance Suite zu schätzen wissen. Hier der Direktlink zum Download der Suite. Der WPF Performance Blog ist immer einen Besuch wert um auf dem laufenden zu bleiben.

 

Technorati-Tags: |

.NET GUI Community

19.04.2008 11:43:00 | Ozgur Aytekin

.NET Community rund um alle Graphical User Interface (GUI) Themen.

Auf .NET GUI, der .NET Community, die sich mit der Entwicklung von grafischen Oberflächen beschäftigt.

Gerade mit dem Aufkommen der Windows Presentation Foundation und Silverlight, haben sich viele neue Möglichkeiten ergeben.

Der Gestaltung von Oberflächen wird höhere Priorität zuteil.

Diese Community bietet die Chance, sich über alle Belange von grafischen Oberflächen auszutauschen.

Einzige Einschränkung: Die Basis muss durch das .NET Framework gegeben sein.

Die Community ist unter der URL: http://dotnet-gui.com/ erreichbar.

WebControls erweitern

17.04.2008 10:00:00 | Jürgen Gutsch

Nachdem im Forum die Frage aufkam, wie man einen LinkButton um einige Features erweitern kann, habe ich mal schnell ein kleines Beispiel zusammengebastelt:

public class MyLinkButton : LinkButton
{
  private string imageUrl;
  /// <summary>
  /// Link des anzuzeigenden Bildes
  /// </summary>
  public string ImageUrl
  {
    get { return imageUrl; }
    set { imageUrl = value; }
  }
  private ImageAlign imageAlign;
  /// <summary>
  /// Ausrichtung des anzuzeigenden Bildes
  /// </summary>
  public ImageAlign ImageAlign
  {
    get { return imageAlign; }
    set { imageAlign = value; }
  }
  /// <summary>
  /// Render Contents überschreiben
  /// </summary>
  protected override void RenderContents(HtmlTextWriter writer)
  {
    Image img = new Image();
    img.ImageAlign = this.ImageAlign;
    img.ImageUrl = this.ImageUrl;
    img.RenderControl(writer);
    base.RenderContents(writer);
  }
}

Diese Klasse erbt von LinkButton und enthält zusätzlich die Eigenschaften ImageUrl (für den Pfad zum anzuzeigenden Bild) und die Eigenschaft ImageAlign (wie beim Image Control für die Ausrichtung innerhalb eines Absatzes, oder einer Zeile zuständig)

Das wichtigste ist allerdings die Methode RenderContents, mit der deren Hilfe man weitere Controls (oder einfach nur Text) innerhalb des Control hinzufügen kann.

Damit unter anderem auch etwas im Designer zu sehen ist, habe ich der Klasse folgende Attribute hinzugefügt:
[Designer("System.Web.UI.Design.WebControls.LinkButtonDesigner, "+
  "System.Design")]
[DataBindingHandler("System.Web.UI.Design.TextDataBindingHandler, " +
  "System.Design")]
[ParseChildren(false)]
[DefaultEvent("Click")]
[DefaultProperty("Text")]
[SupportsEventValidation, ControlBuilder(typeof(LinkButtonControlBuilder))]
[ToolboxData("<{0}:MyLinkButton runat=\"server\">LinkButton</{0}:MyLinkButton>")]
[AspNetHostingPermission(SecurityAction.LinkDemand,
  Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
  Level = AspNetHostingPermissionLevel.Minimal)]
public class MyLinkButton : LinkButton
{
}

Nachdem ich das Control wie folgt in der Seite registriert habe:
<%@ Register Assembly="WebApplication1"
    Namespace="WebApplication1" TagPrefix="cc1" %>

kann es so benutzt werden:
<div>
    <asp:LinkButton ID="LinkButton" runat="server">
        <asp:Image ID="Image1" runat="server"
            ImageUrl="calendar.gif"
            ImageAlign="AbsMiddle" />Calendar
    </asp:LinkButton>
    <br />
    <br />
    <cc1:MyLinkButton ID="MyLinkButton1" runat="server"
        ImageUrl="calendar.gif"
        ImageAlign="AbsMiddle"
        Text="Calendar" />
</div>

Zum Vergleich habe ich oben drüber das gleiche mit herkömmlichen ASP.NET Control zusammengebaut. Die resultierende Ausgabe ist die selbe:

Nur im Designer wird der Unterschied zwischen dem herkömmlichen Konstrukt und dem erweiterten Control sichtbar:

Das Beispiel Projekt (für VS 2008, die einzelnen Dateien können natürlich auch mit VS 2005 angesehen werden) kann hier heruntergeladen werden:
WebApplication1.zip (21 KB)

Mein erster Flug: Frankfurt - Seattle

17.04.2008 00:19:00 | Peter Bucher

Ja, richtig gelesen. Ich bin noch nie auf die Nase geflogen :-)
Aufgrund des MVP Summits bin ich jetzt aber in den Genuss gekommen, meine Flug-Jungfräulichkeit zu verlieren :))

Irgendwie hatte ich davor ein komisches Gefühl, aber drücken konnte ich mich ja nicht mehr, hehe.

Ich hatte ein Fensterplatz und schaute schon beim Start aus dem Fenster. Irgendwie war das gaaanz cool und gar nicht schlimm :-)

Im weiteren Verlauf des Fluges konnte die Langeweile per Entertainment System mit mehr oder weniger aktuellen Kinofilmen vertrieben werden.
Während dem Flug ein paar Fotos geschossen und kurz geschlafen. Der Flug an sich verlief ohne auch nur die kleinste Störung und war im Prinzip wie eine Reise per Bus (Ausgenommen war ein kleines Luftloch, was doch etwas Adrenalin ausgeschüttet hat :).

Das coolste an der Geschichte war die Landung, als der Pilot schräg angeflogen ist (Vor dem Geradebiegen des Fliegers für den Landeanflug :). Ein spezielles Gefühl.
In Konklusion kann ich sagen: Ich habe keine Flugangst und fliege gerne wieder, Spass hats gemacht (-:

Hier noch ein paar Eindrücke vom Flug in Bildern:

 

CIMG2043 CIMG2044
Vor dem Flug
Sicht nach unten, nach dem Start
CIMG2046 CIMG2050
Das legendäre "Flügelfoto" :)
Sieht doch einfach toll aus, über den Wolken
CIMG2057 CIMG2067
Grönland oder sowas (jaa Stefan, konnste mich nicht aus dem Fenster schmeissen^^) Kurz vor der Landung

Von der Schweiz nach Frankfurt

16.04.2008 00:23:09 | Peter Bucher

Donnerstag nach dem Mittag ging ich in Biel auf Zug in Richtung Basel.
Bei Basel musste ich dann umsteigen und wäre bin leider nicht, in einem Stück dann nach Frankfurt Flughafen gefahren.

Ich stieg in den vorderen Zug ein, und die Nachricht das dies nicht der Zug zum Flughafen ist, kam eine Minute vor Abfahrt beider Züge. Na toll ;-)

Egal, in Mannheim ausgestiegen und dort wieder auf den richtigen Zug gesprungen.
Schliesslich war ich in Frankfut im Flughafen. Ein riesen Areal, keinen Durchblick :))

Ich schnappte mir ein Taxi, und hatte das Glück Pech, einen wirklich netten doofen Taxifahrer erwischt zu haben.
Sogar wärend der Fahrt vertraute ich nicht wirklich auf dessen Fahrkünste... aber schlussendlich kam ich beim Hotel an.

Im Hotel klappte das Internet leider nicht, aber ein bisschen Offline tut auch gut :))

Morgen gehts dann auf nach Amerika. Redmond ich komme (-:

Achja, das Hotel war cool, und günstig teuer, sehr teuer... aber cool :)

Hotel

Variable Deklaration und Wert-Zuweisung in Microsoft SQL Server 2008

13.04.2008 08:44:00 | Ozgur Aytekin

Die Variablen Deklaration und Wert-Zuweisung in T-SQL erfolgte in zwei Schritten. Zuerst musste die Variable deklariert und dann der gewünschte Wert zugewiesen werden.

Der folgende Beispielcode wird vielen T-SQL Entwickler bekannt vorkommen:

DECLARE @Variable1 INT
DECLARE @Variable2 NVARCHAR(50)

SET @Variable1 = 100
SET @Variable2 = 'Text Variable'

Neu in Microsoft SQL Server 2008 wurde dieser Vorgang vereinfacht. Es sind nicht mehr zwei Schritten Notwendig um einen Variablen zu deklarieren und einen Wert zuzuweisen.

DECLARE @Variable1 INT = 100
DECLARE @Variable2 NVARCHAR(100) = 'Text Variable'
Wenn die Deklaration und Wert-Zuweisung von den Variablen hintereinander erfolgt, kann auch die folgende Syntax verwendet werden:
DECLARE @Variable1 INT = 100,
        @Variable2 NVARCHAR(100) = 'Text Variable'

Free E-Learning - .NET Framework 3.5 and Visual Studio 2008

12.04.2008 01:00:00 | Ozgur Aytekin

Für eine beschränkte Zeit gibt es für die Technologien

- Windows Workflow Foundation (WF)

- Windows Presentation Foundation (WPF)

- Windows Communication Foundation (WCF)

mit Microsoft .NET Framework 3.5 und Visual Studio 2008 gratis E-Learning Angebot.

https://www.microsoftelearning.com/eLearning/offerDetail.aspx?offerPriceId=213184

Afterlaunch - er ist vorbei

11.04.2008 22:55:04 | Albert Weinert

Aus Sicht eines Veranstalters und Sprechers, schön, schön anstrengend, ein wenig Stress, alles gut verlaufen (stand jetzt :). Somit insgesamt eine gelungene Veranstaltung auf der sich 152 Teilnehmer, 14 Sprecher, 7 Mitarbeiter von Sponsoren sowie ein überall helfender Kassenwart tummelten.

Vielen Dank an alle 174 Personen sowie den Mitarbeitern der Sponsoren die nicht vor Ort waren, das sie diesen Tag möglich gemacht haben.

http://www.afterlaunch.de

Wer mag; Lob bitte hier rein, konstruktive Kritik auch.

Technorati-Tags: ,,

Logoff

10.04.2008 19:19:00 | Peter Bucher

So, Heute ist mein letzter ganzer Tag in der Schweiz für ca 8 Tage.

Morgen nach dem Mittag gehts zuerst per Zug nach Deutschland, Frankfurt, wo ich dann erst mal eine Nacht überleben muss :-)
Danach gehts am Freitag Morgen ab zum Flughafen, wo ich dann endlich mal Stefan Falz und viele andere Kollegen persönlich sehe.

Der Flug führt mich nach Amerika, Seattle, Redmond... ja, ihr denkts euch schon: Microsoft Campus zum globalen Treffen aller MVPs die sich Ferien nehmen können :)

Während diesen 8 Tagen werde ich wohl viel weniger direkte Zeit für Internet und die Community haben,
aber wenn es geht, schreibe ich auch mal einen Bericht oder poste Fotos vom sonnigen verregneten Seattle.

Achja, man glaubts kaum, aber das ist mein erster Flug. Hoffentlich geht das gut :))

Eine neue Community für GUI mit .NET ist online

10.04.2008 14:32:00 | Peter Bucher

Norbert Eder befasst sich jetzt schon eine ganze Zeit mit GUIs unter WindowsForms und auch schon länger mit GUIs und allem was dazugehört unter .NET 3.5, d.h. WPF.

Jetzt hat er eine Community online gestellt, die für den Austausch von GUI-Fragen / -Antworten und -Meinungen bereitsteht.
Ich werde dort - je nach dem wie die Zeit reicht - im ASP.NET GUI Part reinschauen.
Folgend zitiere ich aus dem Willkommensbeitrag aus dem Forum:



Ab sofort steht den deutschsprachigen .NET Communites eine weitere Community zur Seite. .NET-GUI.com. Eine Community, die sich mit der Erstellung von grafischen Benutzeroberflächen beschäftigt.

Unter anderem werden die folgenden Themen behandelt:

  • Windows Forms
  • Windows Presentation Foundation
  • Silverlight
  • Usability

Ziel ist es, eine Plattform zu schaffen, auf der sich alle Beteiligten rund um Ihre Anliegen und Erfahrungen zur Entwicklung von grafischen Oberflächen auf Basis von .NET austauschen können.

Viel Spass auf http://www.dotnet-gui.com/ !

Launch 2008 - Welche Sprachversion des Team Foundation Servers installieren?

10.04.2008 10:24:41 | Christian Binder

Die Teilnehmer der Launch-Veranstaltung in Frankfurt konnten bei der kostenlosen Software zwischen der englischen und der deutschen Sprachversionen wählen.

Da beim Visual Studio Team System 2008 Team Foundation Server (TFS) ein nachträgliches Wechseln der Sprache speziell von deutsch auf englisch technisch nicht möglich ist (siehe auch Plan Language Blog Eintrag), sollte vor der Installation die Sprach-Entscheidung getroffen werden. Neben der Oberfläche sind auch die Projektinhalte von der Sprache betroffen.

Wenn Sie auf der Launch-Veranstaltung eine deutsche Version des TFS gewählt haben, können Sie trotzdem die englische Version installieren.

Bitte gehen Sie dabei wie folgt vor:

(1) Laden Sie die englische TFS Trial Version herunter und installieren Sie diese komplett. Diese finden Sie hier: http://msdn2.microsoft.com/de-de/vstudio/aa700831.aspx

(2) Anschließend die Installation erneut aufrufen (über die Windows-Systemsteuerung), die Option „TRIAL aktivieren“ steht direkt im ersten Dialog zur Verfügung.

(3) Den Key der deutschen TFS-Version aus dem Launch Kit eingeben und damit die englische Version des TFS aktivieren.

Ein ausführlichere Beschreibung finden Sie auch auf Brian Harry´s Blog unter:
http://blogs.msdn.com/bharry/archive/2008/01/15/how-to-i-upg...

 

Chris

Mehrere Sprachen in eine Assembly kompilieren / mergen

08.04.2008 20:49:00 | Peter Bucher

Ich dachte lange, wenn ich ein VB.NET- und ein C#-Projekt habe, geht es nicht, daraus eine einzige Assembly zu erzeugen.
Und wenn, dann nur mit Abstrichen in der Handlichkeit des ganzen, also keine Visual Studio Integration, Debuggin, Intellisense, etc..

Nun, eine kleine Resserche Heute Abend und ich wurde gleich zweimal vom Gegenteil überzeugt.
Vorneweg, ich möchte das im Normalfall natürlich niemandem empfehlen, wenn es jedoch unvermeindlich ist, oder aber Vorteile mit sich bringt, wieso nicht? :-)

Ganz nützlich wenn eine Control Sammlungs Assembly erstellt werden muss, und Controls in VB.NET, wie auch C# bestehen :-)

Hier die erklärenden Links (Englisch):

Die Afterlaunch-Konferenz ist ausgebucht

08.04.2008 12:21:29 | Albert Weinert

Ich freue mich der Welt mitzuteilen dass die Afterlaunch-Konferenz am Freitag den 11. April 2008 restlos ausgebucht ist.

Die glücklichen Ticket-Besitzer werden am Freitag in Köln erwartet, es kann nur großartig werden!

First und FirstOrDefault Operatoren

05.04.2008 23:20:00 | Ozgur Aytekin

Mit beiden Operatoren kann das erste Element aus einer Liste ermittelt werden.

Die Operatoren verhalten sich anders, wenn der Abfrage ein leeres Resultat zurück liefert. Der Operator First feuert eine InvalidOperationException. FirstOrDefault Operator liefert einen NULL-Wert zurück.

In dem folgenden Beispiel wird die AdventureWorks-Datenbank als Datenquelle verwendet. Es wird versucht, mittels folgende Abfrage die Produkt zu ermitteln, welche an die Produktekategorie (ProductCategory) Bikes und Produktesub-Kategorie (ProductSubcategory) Mountain Bikes zugeortned sind. Als letzte Bedingung wird der Listenpris (ListPrice) kleiner als 500 vernwendet.

AdventureWorksDataContext db = new AdventureWorksDataContext();
IQueryable<Product> qry = from pc in db.ProductCategories
                          join psc in db.ProductSubcategories on pc.ProductCategoryID equals psc.ProductCategoryID
                          join p in db.Products on psc.ProductSubcategoryID equals p.ProductSubcategoryID
                          orderby p.ListPrice
                          where pc.Name == "Bikes" && psc.Name == "Mountain Bikes" && p.ListPrice < 500
                          select p;

Die obige Abfrage liefert keine Produkte zurück, weil in der Datenbanktabelle Product kein Produkt die WHERE-Bedingung entspricht.

Wenn jetzt versucht wird, mit dem Operator First den ersten Produkt zu ermitteln, wird eine Exception gefeuert.

image

Dagegen, wenn der Operator FirstOrDefault verwendet wird, wird als Resultat einen NULL-Wert zurück geliefert.

image

Meine Empfehlung ist, den FirstOrDefault Operator verwenden, wenn das Resultat nicht immer einen Wert zurück liefert.

String.GetHashCode und IIS7 auf Windows Server 2008 x64

03.04.2008 22:51:30 | Jürgen Gutsch

Ein interessantes "Feature" habe ich gefunden, als ich nach erfolgreicher Installation des Windows Server 2008 meine alten Webs wieder einrichten wollte. Und zwar konnte ich mich in keines meiner sharpcms.net Webs mehr einloggen, wenn ich diese über den IIS7 aufgerufen habe. Aufrufe der Webs über den in im VS2008 integrierten Webservers liefen problemlos.

Nach längerem debuggen und suchen im IS7, fand ich dann die Lösung:
Der Grund hierfür ist, das die Methode String.GetHashCode die Strings anders Kodiert wenn die Anwendung im IIS7 läuft, als wenn die Anwendung im IIS6.1, oder im integrierten Webservers des VS2008 läuft.

Wieso im IIS7 diese Stolperfalle eingebaut ist weis ich nicht. Die Lösung ist auf jeden Fall die, dass ich in den Erweiterten Einstellungen des aktuellen ApplicationPools das Feld "Enable 32-Bit Applications" auf "true" stellen muss und schon werden meine Passwörter wieder wie vorher kodiert.

IISIIS7 Application Pool Advanced Settings

Man könnte fast annehmen, dass es was mit der 64-Bit Version des Server zu tun hat, allerdings hatte ich das Problem nicht mit der 64-Bit Version von Windows XP. Möglicherweise hat der IIS unter XP, sowie der der integrierten Webservers der IDE standardmäßig 32-Bit Applications zugelassen...

Ein hexadezimaler Farbcode als String in Color konvertieren

02.04.2008 19:21:00 | Peter Bucher

Das ist zwar etwas, das eher selten gebraucht wird, trotzdem nett wenns im Accessoire ist :-)

System.Web.UI.WebControls.WebColorConverter

Eine Hilfsfunktion dazu (Wäre auch nett als Extension Method [Natürlich mit entsprechender Namenskonvention]):

/// <summary>
/// Konvertiert einen Farbwert der als String im Hex-Format
/// vorliegt, in ein System.Drawing.Color Wert.
/// </summary>
/// <param name="hex">Farbcode als Hex String</param>
/// <returns>Farbe vom Typ System.Drawing.Color</returns>
public static Color GetColorFromHexString(string hex) {
    if(!hex.StartsWith("#"))
        hex = "#" + hex;

    WebColorConverter c = new WebColorConverter();
    return (Color)c.ConvertFrom(hex);
}

Beispielanwendung:

Color c = Tools.GetColorFromHexString("#ffffff"); bool b = c.Equals(Color.White); // <- true

TechDays'08 ein Rückblick

02.04.2008 06:55:00 | Jürgen Gutsch


Am 19. und 20. Februar fanden in Basel die TechDays'08 statt auf denen das Neueste aus den Bereichen .NET, Silverlight, SQL Server, Live und vielen anderen vorgestellt wurden. Highlight sollte die am Mittwochabend stattfindende Launch Party sein. Da ich den Fehler machte und auf der deutschen Seite des Rheins nach Basel gefahren bin kam ich 20 Minuten zu spät an und musste die Keynote auf einer Leinwand in einem anderen Saal mit verfolgen.

Der verpasste Start wurde gleich durch die erste Session von Ronnie Sauermann, zum Thema Silverlight 2.0, wieder wett gemacht. Nach dieser Session traf ich dann auch endlich Thomas Huber und Peter Bucher von ASP.NET Zone. (Leider gibt es noch keine ASP.NET Zone T-Shirts... wär ganz lustig gewesen...)

Die zweite Session zum Thema VS2008 & .NET 3.5 konnten wir leider nicht sehen, da der Saal bereits voll war. Ebenfalls interessant war die Session von Sascha Corti zum Thema VS2008 für Webanwendungen. An diesem Abend besuchte ich außerdem noch die Sessions "Windows Server 2008 und IIS 7 for Devlopers" (von Alain Schneble) und VSTS 2008 & Rosario (von Roger Bösch)

Und die Launch Party? Ja, die Launch Party die war interessant... :-) Im angekündigten Weltrekordversuch ging es darum das ein Jonglierlehrer es schaffen sollte innerhalb von 33 Minuten so vielen Laien wie möglich das Jonglieren mit 3 Bällen bei zu bringen. Das von Microsoft angestrebte Ziel von 111 Jongleuren wurde weit übertroffen. Am Ende waren es dann 240 jonglierende IT Professionals (mehr dazu). Leider war das alles was es so an Party gab und wir (Thomas, Peter und ich) flüchteten uns in die Stadt, auf die Suche nach einem gemütlichen Bier.

Am folgenden Tag hab ich noch folgende Sessions besucht:
Windows Live Services (Part 1 und 2) - Stefano Mallè
WPF: Expression Blend for Developers - Christian Moser
Spricht Ihre Anwendung Open XML - Jens Häupel
Become a Build Master (Build Automation mit TFS) - Roger Bösch

Ein überraschend interessantes Thema war Open XML, vor allem wenn man bereits unter Office 2003 mit den verschiedenen Office Markup Languages gearbeitet hat (Office XML, bzw. WordML und ExcelML). Gerade im Web Bereich, wo ein Office nichts auf einem Webserver zu suchen hat, kann jetzt ein MS Office Dokument erstellt werden.

Fazit:
Die Sessions waren alle zusammen hervorragend, leider aber nicht die Location. So waren die einzelnen Sessions teilweise zu weit auseinander, so das 20 bis 30 Minuten Pause kaum bis garnicht ausreichten um zwischendurch etwas zu Trinken, oder zu Essen zu holen, oder mit Anderen über die letzte Session zu Diskutieren. Teilweise waren auch einfach die Schlangen vor den Essensausgaben zu lang. Ebenso beim Mittagessen: Als wir am ersten Tag mehr als eine halbe Stunde angestanden sind, hatten wir am zweiten Tag - nachdem wir die Schlange gesehen hatten - beschlossen außerhalb essen zu gehen.

Übrigens sind seit Montag Bilder von der Veranstaltung und Präsentationen, sowie Demos zu den einzelnen Sessions online.

Ein simples Listen Menü mit ASP.NET

01.04.2008 19:18:00 | Peter Bucher

Das mitgelieferte Menü Control von ASP.NET rendert Tabellen und vieles unnötiges Markup.
Mit den CSS Adapters wird das ganze zwar ausgebogen, erfordert aber eine Installation bzw. Einrichtung im Projekt und ist vielen (auch mir) nicht so symphatisch.

Nicht nur aus oben genanntem Grund, sondern auch weil es eine suboptimale Lösung darstellt, der generierte Markup der Adapters ist m.E. auch noch nicht optimal.

Ein Menü braucht ja jeder, und korrektes und einfaches Markup ist beim Menü noch viel wichtiger, als dies bei anderen Seitenteilen der Fall ist.
Im Prinzip liefert ASP.NET schon ein komplettes fast komplettes Menü mit, ohne es danach zu Benennen ;-)

Ich meine damit das "BulletedList" Control. Wenn dieses leicht abgeändert wird, wird daraus ein super funktionales Menü, das deklerativ, per Code oder sogar per DataBinding mit Daten gefüllt werden kann.

Natürlich hat dieses Control dann die Beschränkung auf eine Dimension, doch vielfach reicht dies aus.
Ansonsten muss die ganze Gschicht dann auf einer anderen Basis aufgebaut werden.

Genug der Worte, sehen wir uns den Code an...

web.config (Beispiel siehe hier, geht aber auch in der Seite selber, für eine Seite):

<add tagPrefix="pb" namespace="pb.Web.UI.WebControls" assembly="ListMenuTest"/>

ASPX:

<pb:ListMenu ID="testMenu" runat="server">
    <asp:ListItem Text="Home" Value="?url=1" />
    <asp:ListItem Text="Produkte" Value="?url=2" />
    <asp:ListItem Text="Kontakt" Value="?url=3" />
    <asp:ListItem Text="FAQ" Value="?url=4" />
</pb:ListMenu>

Ein bisschen CSS:

#testMenu {
 list-style-type: none;
 border: 1px dotted gray;
 padding: 15px;
 width: 200px;
}


#testMenu a {
    font-family: Tahoma;
    font-size: 1.5em;
    font-style: oblique;
    color: Black;
    border-left: solid 20px #878787;
    padding-left: 4px;
   
    text-decoration: none;
}

#testMenu a.active,
#testMenu a:hover {
    border-left: solid 20px #000446;
    padding-left: 4px;
    color: #878787;
}

Test Code für das Beispiel im Codebehind der Testseite:

protected void Page_Load(object sender, EventArgs e) {
    string activeValue = this.Request.QueryString["url"] as string;
    if (activeValue != null)
        this.testMenu.ActiveValue = "?url=" + activeValue;
}

Das Control selber:



using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace pb.Web.UI.WebControls
{
    public class ListMenu : BulletedList
    {
        private string _activeValue;
        public string ActiveValue {
            get { return this._activeValue; }
            set { this._activeValue = value; }
        }

        protected override void RenderContents(HtmlTextWriter writer) {
            foreach (ListItem item in this.Items) {
                writer.WriteFullBeginTag("li");
                writer.AddAttribute("href", item.Value);
                if (item.Value == this._activeValue) {
                    writer.AddAttribute("class", "active");
                }
                writer.RenderBeginTag("a");
                writer.Write(item.Text);
                writer.RenderEndTag();
                writer.WriteEndTag("li");
                writer.Write(Environment.NewLine);
            }
        }
    }
}

Wie man sehen kann, nehme ich das BulletedList Control, füge eine neue Eigenschaft "ActiveValue" hinzu und nehme das Rendering des Contents (Alle innenliegenden <li>-Tags) selber in die Hand.
Hierbei wird dem aktiven Item jeweils die CSS Klasse "active" zugewiesen.

Zuweisung der Styles erfolgt hier jetzt über die ID, die ID kann sich - je nach Gegebenheit - aber ändern, das heisst am besten eine Klasse dafür nehmen, oder über das umschliessende Div ansprechen.

Thats it, viel Spass damit!

Beispielanwendung gibts hier zum Download

ImgBurn - Schnell ein Image Brennen

01.04.2008 19:03:00 | Peter Bucher

Wenn keine Brennsoftware zur Verfügung steht, oder keine erwünscht ist, wäre es doch schön, eine kleine feine Lösung zu haben.
Ich habe meine Lösung mit ImgBurn gefunden und möchte sie hier weiterempfehlen.
Das Ding läuft auch auf Vista und Server-Betriebssystemen.

Zitat:

ImgBurn is a lightweight CD / DVD / HD DVD / Blu-ray burning application that everyone should have in their toolkit!

 

Ganze 1.8 Megabyte bringt das Programm auf die Waage, genau nach meinem Geschmack :-)

Zum zweiten mal mit dem Microsoft MVP Award ausgezeichnet

01.04.2008 17:29:43 | Albert Weinert

Vor ein paar Minuten in meinem Postfach.

Sehr geehrte(r) Albert Weinert,

Herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft® MVP Award 2008 verleihen zu können. Mit dem MVP Award danken wir Ihnen für Ihren Einsatz für die Community, mit dem Sie Tag für Tag dazu beitragen, das Leben der Menschen zu bereichern und die Branche erfolgreicher zu machen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen Communities zum Thema Microsoft ASP/ASP.NET im vergangenen Jahr hoch ein.

Da sage ich danke!

Regeln | Impressum