Folgende Mail möchte ich der Community jetzt nicht vorenthalten:
Diesen Satz (nur Bezogen auf das Bau-Wesen) hab ich gestern (zu spaeter Stunde) im Fernsehen gesehen.
Damit ist gemeint, dass es die Leute gewohnt sind, in den Supermarkt zu gehen und sich einen Videorekorder zu kaufen. Dieser wird perfektioniert produziert und Massenhaft verkauft.
Genau das funktioniert bei Software-Projekten eben nicht (oder wie die Person gemeint hat, beim Bau), weil eben jedes Projekt eine Individual-Anforderung ist. Und waehrend des Projektes die Probleme auftauchen geloescht werden muessen.
Ich fand den Satz einfach nur gut und wollte den hier mal publizieren ;-)
Software-Projekte sind keine Videorekorder!
In diesem Sinne, viel Spass :)
Nun ist es offiziell. Wir haben einen neuen Sponsor für das INETA Deutschland Speakers
Bureau!!! Die Firma Telerik hat sich nicht nur
bereit erklärt, das Budget aufzustocken, sondern wird auch jedem genehmigten Event
eine Lizenz der Telerik Premium Collection inkl.
1 Jahr Support im Wert von $1.299 zur Verlosung beilegen! Klasse! :)
Ab heute können wieder Reisekostenzuschüsse für Sprecher bei .NET User Group Events
beantragt werden.
Ich will auch gleich die Gelegenheit nutzen, ein paar aktuelle Zahlen des Speakers
Bureaus zu veröffentlichen.
Bis jetzt wurden dieses Jahr wurden insgesamt 26 Event bezuschusst. Insgesamt wurden
seit dem knapp einjährigen Bestehen 53 Events gesponsert. Die Sprecherliste wächst
stetig. Wir haben mittlerweile 14 Sprecher im Speakers Bureau gelistet:
-
Schissler, Thomas
-
Lorenz, Patrick A.
-
Keller, Lars
-
Weigelt, Roland
-
Raacke, Mathias
-
Schwichtenberg, Dr. Holger
-
Weinert, Albert
-
Weber, Torsten
-
Sommer, Oliver
-
Klein, Constantin
-
Dobermann, Mirko
-
Lieser, Stefan
-
Biswanger, Gregor
-
Forkmann, Steffen
Das INETA Deutschland Speakers Bureau sucht noch weitere Sponsoren! Interesse? Dann
schicken Sie mir gern eine E-Mail und wir sprechen über die Möglichkeiten: keller
[at] ineta-germany [dot] org
P.s.:
Ich bin gerade überwältigt, wie hoch der Andrang auf das neue Budget ist. Wie immer
gilt: first come – first serve!
This weblog is sponsored by netcreate OHG.
Wir erklären, wie das Internet
funktioniert, was ein Browser ist, was man bei der Benutzung beachten muss, was es
mit Webseiten und deren Darstellung auf sich hat und geben Tipps und Tricks im Umgang
mit einem Webbrowser… und beantworten auch die wichtigste aller Fragen: Warum die
Oma von Lukas ihm den Laptop wegnimmt, obwohl er richtig brav und artig war!
Video: Wir erklären das Internet und geben Tipps und Tricks im Umgang mit dem Browser
Weiterführende Links:
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
Wir erklären, wie man Darstellungsprobleme
von Webseiten verhindern kann und liefern interessante Tipps, Tricks und Links für
Webmaster, Web-Designer und Web-Entwickler. Weiterhin beantworten wir Fragen wie:
„Meine Website funktioniert nicht richtig. Wie kann ich das Problem heute beheben?“
oder „Standards - was bedeutet das?“.
Video: Wir erklären wie man Darstellungsprobleme von Webseiten verhindern kann
Weiterführende Links:
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
We explain how the internet
works, what a browser is and what you should be aware of when using it, why the display
of websites can differ in different browser and we share tips and tricks regarding
the use of a webbrowser ...and we also answer the most important of all questions:
why Lukas‘ aunt takes her nephew’s laptop away, even though he was being good!
Video: We explain how the internet works and provide tips and tricks for using
browsers
Related Links:
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
We explain how you can solve browser
display problems and we provide tips, tricks and valuable resources for webmasters,
web developers and web designers. We are answering questions like „My
site isn’t working right, how can I fix it today?“ or „Standards
by default, what does that mean?“.
Video: We
explain how you can solve browser display problems
Related Links:
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
Nur noch sieben Tage und der er geht los, der erste .NET Open Space für 2009 in Blaustein bei Ulm.
Bis jetzt haben sich 65 Personen angemeldet. Somit ist viel Know-How in den unterschiedlichsten Bereichen vor Ort. Wenn ich mir die Teilnehmerliste ansehe verspricht es ein sehr interessantes Wochenende werden bei der Menge an Wissen und Interessen.
Ich selbst werde wohl mindestens eine Session zu ASP.NET MVC vorschlagen, auf der User Group Tour wurde reges Interesse daran bekundet.
Wer sich also nur Ansatzweise für Software-Entwicklung mit .NET Interessiert der sollte es nicht versäumen auch vom 11. bis zum 12. Juli in Blaustein zu sein! Es sind noch wenige freie Plätze vorhanden.
Da so ein Open Space am besten funktioniert wenn man vorher wenigstens schon mal das eine oder andere Wort gewechselt hat, gibt es nun auch ein spontanes Treffen zum kennenlernen am Freitag den 10. Juli 2009. Dies sollte man sich auch nicht entgehen lassen.
Also, wir sehen uns in einer Woche in Blaustein!
Welches Lied läuft da eigentlich im Radio? - Frag doch dein Handy......(read more)
Es war mein zweiter Besuch bei der DNUG Ulm zum
Thema VSTO/OBA. Dieses Mal habe ich verschiedene Einsatzszenarios mit VSTO aufgezeigt.
Mein Vortrag ging über die Interaktion zwischen den MS Office Applikationen und wie
man mit Hilfe von VSTO einfache WorkFlows Händeln kann. Der zweite Teil meines Vortrags
drehte sich um das Deployment von VSTO Lösungen. Abschließend habe ich noch einen
kleinen Ausblick auf die nützlichen Änderungen für VSTO/OBA Entwickler bei VSTO 4
und C# 4.0 gegeben.
Der Abend hat mir großen Spaß gemacht, besonders die lebhafte Diskussion über VSTO!
Danke für die Einladung! Ich komme gern wieder. :)
Hier sind meine Beispiele & Folien:
This weblog is sponsored by netcreate OHG.
Wenn ein Backup von einer SqlServer-Datenbank zurückgespielt wird kann es sein, das anschliessend für die vorher berechtigten Benutzer das Login fehlschlägt.
Im Sql Management Studio kann unter der Funktion "UserMapping" die Berechtigung im Normalfall wieder zugewiesen werden, jedoch kann es eben in diesem Fall zum Fehler 15023 kommen.
Für mehr Details zu diesem Fehler siehe hier und hier, wie man den Fehler beheben kann findet sich in diesem und diesem Blogpost.
Das Anbinden von Daten (aus einer Datenbank zum Beispiel) in eine WPF Listbox geschieht am besten über ein CollectionViewSource Control deklarativ in XAML. Die CollectionViewSource hat den Vorteil, dass an ihr Filter, Sortierungen und Gruppierungen angewandt werden können, die direkt in der ListBox sichtbar werden.
Bei der Gruppierung ist es nun auch möglich sich die Gruppenüberschriften in der ListBox darstellen zu lassen, siehe hier (klicken zum Vergrößern):

Das Gruppieren ist im Check-Event der CheckBox mit diesen Zeilen Code eingestellt und angewandt:
private void CheckBoxGroupBy_Checked(object sender, RoutedEventArgs e)
{
PropertyGroupDescription gd = new PropertyGroupDescription("Country");
CustomerViewSource.GroupDescriptions.Add(gd);
}
[Hinweis, die CustomerViewSource Eigenschaft ist eine Eigenschaft des Windows und dort folgendermaßen deklariert:
public CollectionViewSource CustomerViewSource
{
get
{
return this.Resources["CustomersViewSource"] as CollectionViewSource;
}
}
Sie gibt also die CollectionViewSource, die in den Resourcen definiert ist, zurück! ]
Die ListBox selbst hat ein GroupStyle Template in dem ein TextBlock definiert ist, der die jeweilige Gruppenüberschrift darstellen soll. Die eigentliche Information (Country in diesem Fall) lässt sich einfach über den Path=Name im DataTemplate abfragen, Code-Beispiel siehe hier:
<ListBox Name="lstbxCustomers"
ItemsSource="{Binding Source={StaticResource CustomersViewSource}}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<!-- ... -->
</ListBox.ItemTemplate>
</ListBox>
Dieses Beispiel steht unter http://cid-fd4d63530af59c99.skydrive.live.com/browse.aspx/.Public/Projekte/WPF?uc=1&isFromRichUpload=1 zur Verfügung!
WPF bietet die Möglichkeit beim DataBind Validierung durchzuführen, dazu muss als erstes eine Klasse erstellt werden, die die Validierung durchführt. Die eigene Validierungsklasse ist abgeleitet von ValidationRule und überschreibt die Methode Validate wie im CodeSnippet gezeigt:
class NotANumberValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double d;
if (double.TryParse(value.ToString(), out d))
return ValidationResult.ValidResult;
else return new ValidationResult(false, "Keine Zahl eingegeben");
}
}
Im XAML kann als DataBind Eigenschaft ValidationRules die ValidationRule angegeben werden:
<Binding ElementName="txtbxDivision" Path="Text"
Converter="{StaticResource divideBy2Converter}"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:NotANumberValidationRule />
</Binding.ValidationRules>
</Binding>
An dem Control an dem die Daten gebunden werden, kann zu dem ein ErrorTemplate definiert werden, das im Fehlerfall erscheint. Ist kein derartiges Template definiert wird automatisch ein dünner roter Rahmen um das Control gerendert. Die Überschreibung des Control Templates sind folgendermaßen aus:
<ControlTemplate x:Key="errorTemplate">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Red"
FontSize="12pt">
Fehler
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
Dabei steht der <AdornedElementPlaceholder /> als Platzhalter für das Element, das mit der Fehlermeldung markiert sein soll. Um dem zu validierenden Element das Template zuzuweisen muss die Validation.ErrorTemplate Eigenschaft angesprochen werden. Über Property Trigger können zudem noch weitere Aktionen angeworfen werden (siehe textBoxStyle).
Hier also das Anlegen der TextBox:
<TextBox Name="txtbxNumber" Validation.ErrorTemplate="{StaticResource errorTemplate}" Style="{StaticResource textBoxStyle}" >
<Binding>
<!-- Hier kommt das Binding wie oben beschrieben rein -->
</Binding>
</TextBox>
Und der dazugehörige Style:
<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
Die Bindung Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" Holt die Validierungsfehlermessage aus der Validierungsklasse und zeigt sie im Tooltip der TextBox an.
Das Projekt (inklusive Konvertierungsbeispiel) kann heruntergeladen werden von: http://cid-fd4d63530af59c99.skydrive.live.com/self.aspx/.Public/Projekte/WPF/Validierung.zip
Das Professional Developer College hat eine Umfrage gestartet zur Frage, wie es um die Zufriedenheit in der Softwareentwicklung steht. Ich bin gespannt auf die Ergebnisse, die nach Abschluss der Umfrage in der dotnetpro veröffentlicht werden.
Fazit: Mitmachen!!
NAch dem ich nun seit ca. einer Woch ausschließlich www.Bing.com als Suchmaschine nutze, habe ich die Google-Toolbar deinstalliert und die Live-Toolbar installiert.
Tschüss liebe Kraake, die letzten (fast 10) Jahre waren schön mit Dir....

Wie in diesem Blog bereits an anderen
Stellen erläutert, eignet sich das UIA (UI Automation Framework) sehr gut, um
UI-Tests aufzubauen. Wer sich mit dieser Möglichkeit beschäftigt wird aber früher
oder später auf das Problem stoßen, dass UIA Support bei WinForms Controls nicht flächendeckend
gegeben ist, vor allem bei 3rd Party Controls sieht es da oft eher mau aus.
Ich habe hier beschrieben,
wie man mit einem ServerSide Provider diese Lücken selbst schließen kann. Das Standardvorgehen
sieht dabei vor, dass man ein eigenes Control erstellt, das man dann von dem Ausgangscontrol
ableitet. Diese Vorgehen ist in der Praxis allerdings nicht unproblematisch. Zum einen
muss man die abgeleiteten Controls für jedes neue Release der Ausgangscontrols aktualisieren
und zum zweiten ist es nicht gerade schön in einer bestehenden Anwendung alle Controls
gegen die abgeleitete Variante austauschen zu müssen.
Deshalb möchte ich hier einen alternativen Weg vorstellen. Die Idee beruht darauf,
dass die Controls, denen es an Accesibility fehlt jeweils in ein Panel platziert werden
und auf diesem Panel dann die entsprechenden Patterns implementiert werden. Das Panel
kann die Operationen dann an das Control in seinem Bauch weiterleiten.
Ich habe mal ein Beispiel für Janus Calendar Controls gebaut. Zunächst habe ich mir
ein UIA-Panel erstellt, von dem ich dann die weiteren Panels für die spezifischen
Controls ableiten kann.
1: using System;
2: using System.Drawing;
3: using System.Security.Permissions;
4: using System.Windows.Automation;
5: using System.Windows.Automation.Provider;
6: using System.Windows.Forms;
7:
8: namespace WindowsFormsApplication1
9: {
10: public partial class UIAPanel
: Panel, IRawElementProviderSimple
11: {
12: public UIAPanel()
13: {
14: this.BackColor
= Color.Yellow;
15: this.Height
= 0;
16: this.Width
= 0;
17: this.AutoSize
= true;
18: }
19:
20: [PermissionSetAttribute(SecurityAction.Demand,
Unrestricted = true)]
21: protected override void WndProc(ref Message
m)
22: {
23: //
0x3D == WM_GETOBJECT
24: Int32
param = 0;
25: if (Int32.TryParse(m.LParam.ToString(), out param))
26: {
27: if ((m.Msg
== 0x3D) && (param == AutomationInteropProvider.RootObjectId))
28: {
29: m.Result
= AutomationInteropProvider.ReturnRawElementProvider(
30: Handle,
m.WParam, m.LParam, (IRawElementProviderSimple)this);
31: return;
32: }
33: }
34: base.WndProc(ref m);
35: }
36:
37: #region IRawElementProviderSimple
Members
38:
39: public object GetPatternProvider(int patternId)
40: {
41: if (patternId
== ValuePatternIdentifiers.Pattern.Id)
42: {
43: return this;
44: }
45: else
46: {
47: return null;
48: }
49: }
50:
51: public object GetPropertyValue(int propertyId)
52: {
53: if (propertyId
== AutomationElementIdentifiers.ClassNameProperty.Id)
54: {
55: return "CalendarPanel";
56: }
57: else if (propertyId
== AutomationElementIdentifiers.ControlTypeProperty.Id)
58: {
59: return ControlType.MenuBar.Id;
60: }
61:
62: if (propertyId
== AutomationElementIdentifiers.HelpTextProperty.Id)
63: {
64: return "Help
for CalendarPanel";
65: }
66:
67: if (propertyId
== AutomationElementIdentifiers.AutomationIdProperty.Id)
68: {
69: return this.Name;
70: }
71:
72: if (propertyId
== AutomationElementIdentifiers.IsEnabledProperty.Id)
73: {
74: return true;
75: }
76:
77: else
78: {
79: return null;
80: }
81: }
82:
83: public IRawElementProviderSimple
HostRawElementProvider
84: {
85: get
86: {
87: return AutomationInteropProvider.HostProviderFromHandle(Handle);
88: }
89: }
90:
91: public ProviderOptions
ProviderOptions
92: {
93: get
94: {
95: return ProviderOptions.ServerSideProvider;
96: }
97: }
98:
99: #endregion
100:
101: }
102: }
Dieses Panel stellt einen ServerSide Provider zur Verfügung. Wir können nun von diesem
Control ableiten und ein entsprechendes Pattern, z.B. das SetValue Pattern implementieren:
1: using System;
2: using System.Windows.Automation.Provider;
3: using System.Windows.Forms;
4:
5: namespace WindowsFormsApplication1
6: {
7: public partial class CalendarPanel
: UIAPanel, IValueProvider
8: {
9: private Janus.Windows.Schedule.Calendar
control;
10: public Janus.Windows.Schedule.Calendar
Control
11: {
12: get
13: {
14: if (control
== null)
15: {
16: if (this.Controls.Count
> 0 && this.Controls[0].GetType() == typeof(Janus.Windows.Schedule.Calendar))
17: control
= (Janus.Windows.Schedule.Calendar)this.Controls[0];
18: }
19: return control;
20: }
21: }
22:
23: #region IValueProvider
Members
24:
25: public bool IsReadOnly
26: {
27: get
28: {
29: return false;
30: }
31: }
32:
33: public void SetValue(string value)
34: {
35: this.BeginInvoke((MethodInvoker)delegate()
36: {
37: DateTime
date = DateTime.Parse(value);
38: Control.SelectionRange
= new Janus.Windows.Schedule.DateRange(date, date);
39: });
40: }
41:
42: public string Value
43: {
44: get
45: {
46: return Control.SelectionRange.End.ToShortDateString();
47: }
48: }
49:
50: #endregion
51: }
52: }
Wenn wir nun das Calendar_Control nicht direkt auf unserer Form platzieren, sondern
in einem solchen CalendarPanel ablegen, können wir eine Automatisierung über die UIA
gegen dieses Panel implementieren. Was nun noch optimiert werden soll, ist dass die
ganzen Controls nicht händisch in die jeweiligen Panels platziert werden sollen, sondern
dies soll nach Möglichkeit automatisiert werden. der Ansatz hierbei ist, dass alle
Controls auf der Form beim Laden untersucht werden und für die gewünschten Controls
dynamisch entsprechende Panels erzeugt werden sollen, in die dann die Controls platziert
werden. Dieser Ansatz bietet zudem den Vorteil, dass man die UIA-Panels nur dann nutz,
wenn man UI-Test ausführen möchte. Bei der Release-Version sind diese dann nicht enthalten.
Zwar unterscheidet sich dadurch Release und Test-Version geringfügig, jedoch sollten
diese Implikationen vernachlässigbar sein, vor allem dann, wenn beim Entwickeln komplett
auf die Panels verzichtet wird und diese wirklich nur für die UI-Tests genutzt werden.
Der Code dazu sieht dann so aus:
1: private void PlaceControlsIntoPanel(Control.ControlCollection
controls)
2: {
3: Panel
uiaPanel;
4:
5: foreach (Control
automationControl in controls.OfType<Control>().ToList())
6: {
7: switch (automationControl.GetType().ToString())
8: {
9: case "Janus.Windows.CalendarCombo.CalendarCombo":
10: {
11: uiaPanel
= new CalendarComboPanel();
12: break;
13: }
14: case "Janus.Windows.Schedule.Calendar":
15: {
16: uiaPanel
= new CalendarPanel();
17: break;
18: }
19: default:
20: {
21: if (automationControl.HasChildren)
22: {
23: PlaceControlsIntoPanel(automationControl.Controls);
24: }
25: continue;
26: }
27: }
28: uiaPanel.Name
= "p_" + automationControl.Name;
29: uiaPanel.Top
= automationControl.Top;
30: uiaPanel.Left
= automationControl.Left;
31: uiaPanel.Controls.Add(automationControl);
32: automationControl.Top
= 0;
33: automationControl.Left
= 0;
34: controls.Add(uiaPanel);
35: }
36: }
Wird die Anwendung dann inkl. Test-Client ausgeführt, sieht das so aus:
Ich hatte gestern bereits mit einem kleinen Problem zu kämpfen, welches sich aber
recht leicht beheben lässt.
Nachdem man eine neue Compute-Node hinzugefügt hat, und einen Framework-Test ausgeführt
hat, kam es zu folgenden Fehler:
Exception thrown while executing RunDiagnostic: Could not load file or assembly
'file:///C:\Program Files\Microsoft HPC Pack 2008 R2\Bin\CCPPSH.dll' or one of its
dependencies. The system cannot find the file specified.
System.IO.FileNotFoundException
Ein einfaches Nach-Kopieren der Dateien genügt leider nicht. Um sich Abhilfe zu schaffen
empfehle ich folgende Methode:
Als erstes sollte man die betroffene Node offline nehmen, im Cluster Manager also
“Take Offline” mit einem Rechtsklick auf die Node auswählen.
Danach kopiert (z.B. per Remote Desktop und Kopieren/Einfügen) ihr das HPC Pack
2008 R2 auf die betroffene Node. Dafür habe ich mir einen Ordner “C:\Install” angelegt.
Dann startet ihr im Unterordner “C:\Install\HPC Pack 2008 R2 CTP\HPCPack\setup” die
MSI-Installation “ cpp_x64.msi mit [Rechsklick –> Install]. Den Installations-Dialogen
folgend wird darauf das HPC Pack wieder deinstalliert.
Dieser Schritt ist nötig, um eine Neuinstallation zu beginnen. Dies tun wir mit der
setup.exe im übergeordneten Ordner.
Bei der Installation wählt ihr “Join an existing HPC cluster by creating a new compute
node”.
Danach gebt ihr noch den hostname eurer Head-Node ein. In meinem Fall ist dies “MSHPC”.
Die Client Tools habe ich ebenfalls mit installiert.
Je nach gewählter Topologie kann man sich entscheiden, Microsoft Update zu nutzen.
In meinem Fall hab ich es deaktiviert, weil das Cluster-Netzwerk von der Außenwelt
getrennt ist.
Nun kann die Node wieder online geschaltet werden, und siehe da, alle Tests sollten
erfolgreich verlaufen.
Vorgestern verpasste ich abends den Zug. Der Grund war relativ einfach: ich bin zu
spät los gegangen. Die Ursache hierfür lag darin, dass ich mehrfach versuchen musste
meine geänderten Quellcode in unser Subversion Repository zu commiten. Leider erhielt
ich während des Commits jedes Mal die Fehlermeldung:
"Can't open file: [subversion dir]\tempfile.tmp Access is Denied"
Zum Glück kannte Google die Antwort.
Kurz zusammengefasst:
Die Fehlermeldung wurde durch den Virenscanner (in meinem Fall McAfee) verursacht.
Dieser meinte nämlich Zugriffe auf die temporäre Subversion Datei blockieren zu müssen.
Nach der Deaktivierung konnte ich meine Quellcodes sofort einchecken. Schade nur,
dass der Zug schon weg war ...
blog.codemurai.de © André Krämer |Impressum | Abonieren
Beim Entwickeln einer Webplattform macht man ja gerne den einen oderanderen HTML Fehler.
Auch wenn mir das immer seltener passiert, ist es dennoch schön wenn man gleich Probleme mittels Holzhammermethode mitgeteilt bekommt.
Bekanntlich kann man in Page Render den HTML-Code abgreifen.
Wenn man daraus ein XElement generieren kann, ist der Code zumindest schon mal valiedes XML.
Wenn dies nicht funktioniert lasse ich mir die Fehlemeldung ausgeben und kann de Fhler gleich korrigieren.
Kleiner Nebeneffekt:
Der HTML-Code ist absolut perfekt eingerückt und die Struktur klar ersichtlich, auch wenn man viele Usercontrols zusammensteckt.
Ob man dies in einer Live-Website einsetzt ist sicherlich fraglich.
1
2 Partial Class _Default
3 Inherits System.Web.UI.Page
4
5
6
7 Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
8
9 Dim sb As StringBuilder = New StringBuilder
10 Dim sw As IO.StringWriter = New IO.StringWriter(sb)
11 Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
12
13 MyBase.Render(htw)
14
15 Dim PageHTML As String = sb.ToString().Replace("<br>", "<br/>")
16
17
18 Try
19 'Bei UpdatePanelanfragen ist kein <body im Code.
20 'Diese Anfragen wollen wir nicht verändern
21 If PageHTML.Contains("<body>") Or PageHTML.Contains("<body ") Then
22
23 PageHTML = PageHTML.Replace("<script>", _
"<script type=""text/javascript"">")
24 PageHTML = PageHTML.Replace("><", "> <").Replace(" ", " ")
25
26 'xElement erstellen:
27 Dim x As XElement = XElement.Parse(PageHTML)
28
29 Dim xString = x.ToString.Replace(vbCr, vbLf).Replace(vbCrLf, vbLf)
30
31 While xString.Contains(vbLf & vbLf)
32 xString = xString.Replace(vbLf & vbLf, vbLf)
33 End While
34
35 'Der Doctype wird im XElement entfernt... also neu hinzufügen
36 Dim Header = "<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN""" & _
37 " ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"">"
38 output.Write(Header & vbCrLf & xString)
39 Exit Sub
40 Else
41 'Bei UpdatePanelanfragen ist kein <body im Code.
42 'Diese Anfragen werden unverändert zurückgegeben
43 output.Write(PageHTML.ToString)
44 Exit Sub
45 End If
46 Catch ex As Exception
47 '################### Hier schlägt der Holzhammer zu!
48 Response.Write(ex.Message)
49 output.Write(PageHTML.ToString)
50 End Try
51
52 End Sub
53 End Class

Gestern habe ich mich mal an den neuen Windows HPC Server 2008 R2 als CTP Version
herangewagt.
Dafür hergehalten hat ein kleiner Test-Cluster, den ich von meiner Uni dafür bereitgestellt
bekommen habe.
Es handelt sich dabei um 3 Supermicro Nodes, mit jeweils 2x2 Cores (Amd Opteron) Prozessoren.
Die Headnode verfügt über 32GB Ram, die Compute-Nodes jeweils 8.
Zur Zeit habe ich also nur 2 Compute-Nodes, es können aber ohne Probleme weitere nachgezogen
werden.
Im Rahmen meiner Seminararbeit werde ich einen Block-orientierten Gauss-Algorithmus
mit MPI/MPI.NET entwickeln, einmal in C und einmal in C#, und die Performance-Unterschiede
auf Linux, Windows, Managed und Unmanaged miteinander vergleichen.
Auf was für Hürden ich eventuell mit der CTP des Windows HPC Server 2008 R2 treffe,
werde ich euch in der nächsten Zeit hier in meinem Blog mal berichten.
Ergänzend zum Artikel “Schrödingers Katze” möchte ich noch erwähnen, dass, falls das msExUserCulture AD-Attribute nicht gesetzt ist, die Spracheinstellung im Internet Explorer die entscheidende Rolle für die Default-Sprache spielen. Stehen die auf “deutsch”, wird per Default beim ersten Logon an OWA “deutsch” ausgewählt. Ist das msExUserCulture Attribut aber gesetzt, kommen die Browser-Settings nicht zum tragen:

Seit längerem verfolge ich die Verwendung der Microsoft Concurrency Runtime. Für mich war die CCR immer ein Bestandteil von Microsoft Robotics Studio. Gestern habe ich dann einfach mal meinen Kollegen Frank Prengel angesprochen, wie man denn die CCR Lizenztechnisch in seine eigenen Projekte einbinden kann. Muss man hierzu Microsoft Robotics Studio besitzen?
Nein, es gibt ein dediziertes Lizenzierungsmodell. Auf der Seite “Get Microsoft CCR & DSS Toolkit” stehen die Lizenzbedingungen und es gibt auch die Möglichkeiten die Lizenz online zu kaufen.
Weitere Information auf der Seite Introducing “Microsoft CCR and DSS Toolkit 2008 R2”
Nach dem mein Kollege und ich uns heute ein neues Projekt bei CodePlex erstellt hatten, war ich schon sehr gespannt ob und wie die Verbindung aus meinem Visual Studio 2010 B1 zum CodePlex TFS funktioniert. Die Anleitung auf CodePlex ist auf jeden Fall leicht und auch für Ungeübte schnell zu verstehen. Beim Verbinden mit dem TFS gibt es auch nicht wirklich viel, was man/Frau falsch machen koennte :-)
Leider bekam ich aber mit dem ersten Versuch sich auf den CodePlex-TFS zu verbinden die folgende Fehlermeldung:
The ServicePointManager does not support proxies with the https scheme.

Oha, was nun? OK, ich begab mich dann mit Hilfe der Suchmaschine meiner Wahl auf die Suche nach einer Lösung. Und siehe da, das Problem ist bekannt. Es gibt einen Bug in der BETA1 von VS2010 der aber mit der BETA2 (wann auch immer diese erscheinen mag) behoben sein soll. Martin Hinselwood hat auf seinem Blog eine Beschreibung veröffentlicht, wie man sich trotz des Bugs in VS2010 Beta1 mit dem TFS von CodePlex verbinden kann. Ich möchte hier eine deutsche Anleitung veröffentlichen.
- Sollte VS2010 noch geöffnet sein, muss es auf jeden Fall beendet werden.
- Für eine Verbindung zum CodePlex-TFS ist ein https-Verbindung notwendig. Damit dies mit VS2010 Beta1 funktioniert, müssen in der Windows-Registrierung zwei neue Schlüssel mit entsprechenden String Values eingefügt werden. Dazu öffnet man das Programm Registry Editor –> dazu Run (Ausführen) öffnen (Windows-Taste + R) und regedit eintippen. Dann OK klicken.
- In der Windows-Registrierung trägt man den Schlüssel RequestSettings einmal für den TFS und einmal für VS2010 ein. Die vollständigen Pfade in der Windows-Registrierung müssen dann unter einem 32Bit-System wie folgt aussehen
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TeamFoundationServer\10.0\RequestSettings
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\TeamFoundation\RequestSetting
Und auf einem 64Bit-System sehen die vollständigen Pfade dann so aus:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\TeamFoundationServer\10.0\RequestSettings
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\TeamFoundation\RequestSettings
- Nun trägt man in den beiden neuen Schlüsseln den String Value BypassProxyOnLocal mit dem Value False ein.
- Nun kann man VS2010 neu starten und über den Team-Explorer die Verbindung zum CodePlex-TFS aufbauen.
Wunderbar! Es funktioniert also doch. Hab ich ja gewusst :-) Also dann, ich wünsche allen Lesern meines Blogs gutes Gelingen bei Ihren Projekten mit VS2010. Wenn noch Fragen zu diesem Thema offen sind, dann einfach eine Mail an mich.
TOM_MUE
Kürzlich war im
Netz zu lesen, was so alles an Bibliotheken in der Webentwicklung eingesetzt wird. Hierbei verwundert es nicht sonderlich, dass jQuery - wahrscheinlich auch durch die
Ankündigung von Microsoft, jQuery in der nächsten Visual Studio Version von Haus aus zu unterstützen - derzeit einen regelrechten Hype in der ASP.NET Entwicklung erlebt.
Auf MSDN ist eine neue Ausgabe vom PWA (Pragmatic Web Architecture) von Patrick A. Lorenz erschienen, das ASP.NET 3.5 fokusiert.
Ich finde das Konzept gut gelungen und die vorherige Ausgabe der Webcast-Serie (Aus dem Jahre 2006) war sehr gut gemacht. Darum empfehlen ich allen die sich für eine pragmatische Architektur mit ASP.NET interessieren, da reinzuschauen.
Zitat:
Grundkonzept von PWA ist eine dem Projekt angepasste, flexibel erweiterbare Architektur für Web-Applikation. Seit über sechs Jahren kommt PWA nicht nur bei der PGK sondern auch vielen anderen Unternehmen erfolgreich zum Einsatz. Bereits 2006 wurde das Konzept mit einer umfangreichen Webcast-Serie, Artikeln und Vorträgen vorgestellt. Mit .NET hat sich auch PWA über zeit verändert. Die neue Webcast-Serie stellt PWA basierend auf ASP.NET 3.5 SP 1 und mit einer neuen Beispielapplikation vor.
Die Webcasts und Quelltexte können direkt von der Firmen-Webseite von Patrick heruntergeladen werden.
Wenn MSTest als UnitTest-Framework benutzt wird, kann unter Umständen folgende Meldung beim Ausführen der Tests auftreten:
VSTestHost.exe has stopped working
Wie man auf englischen Blogs (und witzigerweise auf StackOverflow.com ;-)) lesen kann, liegt das in den meisten Fällen daran das ein Test eine StackOverflowException auslöst die durch eine
Endlosrekursion ausgelöst wird.
Sowas bspw.:
[TestMethod]
public void BrokenTest()
{
Test();
}
private void Test()
{
Test();
}
Natürlich ist der Fehler in den meisten Fällen nicht so einfach sichtbar.
Bei den Testergebnissen, mit der Erkenntnis was man zuletzt geändert hat und mit dem Versuch die einzelnen Tests auszuführen
und zu schauen ob ein Fehler kommt, kann man den Fehler finden.
Wer schon mal extensiver mit XAML (WPF) zu tun gehabt hat, der weiss: Debugging von DataBinding ist nicht so ganz trivial…
Ich hatte heute einen ganz simplen Cut-n-Past Error: Habe ein Binding Expression der Form
<Label Text="{Binding Path=Test}" />
in ein MultiBinding eingefügt… wer nun schon mal mit MultiBindings gearbeitet hat weiss, dass man dazu nicht die “Kurzform” mit den geschweiften Klammern verwendet, sonder das ganze in die “Elemente” reinschreibt… also aus dem obigen Beispiel wird dann ein
<Label>
<Label.Text>
<Binding Path="Test}" />
</Label.Text>
</label>
So… das sieht ja einfach aus
jetzt hab ich aber beim Copy-and-Paste dummerweise die geschweifte Klammer am Ende mitkopiert… dann noch einige Zeit weitergearbeitet… und dann wollte ich starten… lies sich auch alles wunderbar compilieren…
Nach dem Start kam aber das böse Erwachen…. ich hab min. 1 Stunde gesucht (und dabei in den tiefen des .NET-Source-Codes debuggt) bis ich den Fehler gefunden habe.
Der Grund: Es kam nicht wie sonst üblich eine Debug-Ausgabe, dass er das Property “Test}” nicht finden kann!
Sondern es kam eine “System.FormatException”… so und jetzt Ihr
(nein, das war schon die InnerException!)
Also, nach langem suchen hab ich tatsächlich ein Bug in WPF gefunden 
Wenn Trace-Ausgaben aktiv sind, dann wird der Text in “Path” einfach ungeprüft der StringBuilder.AppendFormat-Methode als Formatstring übergeben… da aber in meinem Fall eine geschweifte Klammer drin war, konnte der String natürlich nicht erfolgreicht formatiert werden… deshalb die Exception (die mir aber nun mal gar nicht weitergeholfen hat).
Hab es mal gemeldet:
VS2008-SP1: FormatException in MS.Internal.AvTrace if Binding.Path contains curly braces…
VS2010-B1: FormatException in MS.Internal.AvTrace if Binding.Path contains curly braces…
Bitte abstimmen, ob Ihr den auch wichtig findet… (ich persönlich finde ja das ganze Debuggen des DataBindungs hundsmiserabel).
Neulich habe ich eine Lanze dafür gebrochen, zwei Probleme der Softwareentwicklung auf einen Streich zu lösen. Das würde Software zukunftsfähiger machen. Denn Abhängigkeiten und Synchronizität sind Behinderungen auf dem Weg in eine glückliche Projektzukunft. Das Mittel für diese “Wundertat”? Asynchrone Flows, d.h. Funktionseinheiten nicht mehr statisch voneinander abhängig machen und auch nicht
Vor einigen Tagen hatte ich darüber spekuliert, wie zufrieden wir Softwareentwickler wohl so mit unseren Jobs sind. Daraufhin gab es einige Einsendungen von Fragebogenergebnissen nach dem DGB-Fragebogen zur Jobzufriedenheit. Das hat mich ermutigt und ich habe mit dem Professional Developer College nun die Aktion etwas erweitert: Jetzt gibt es eine “echte” Umfrage mit Gewinnen, die unter den
Auf der Suche nach Unterstützung für sichereren Code im Bezug auf Verwundbarkeiten für weit verbreitete Attacken, wie z.B. Cross-Site Scripting (XSS), SQL Injection oder XPath Injection, bin ich heute über einen vermeintlich noch relativ neuen Download gestolpert. Das Microsoft Code Analysis Tool .NET v1 steht nämlich als CTP zur Verfügung. Dahinter verbirgt sich ein Visual Studio 2005/2008 snap-in, das dabei hilft Sicherheitslücken in einer Managed Code (C#, Visual Basic .NET, J#) Anwendung zu identifizieren. Das Ganze gibt es auch in einer 64-bit Version.
Nachdem ich dazu einen Beitrag im Security Development Lifecycle Blog gefunden habe sieht es zwar so aus, als wäre der Download schon etwas länger verfügbar und es gab nur eine Aktualisierung, aber trotzdem ist das Tool wahrscheinlich noch nicht allgemein bekannt. Im entsprechenden Blog-Artikel gab es dafür dann allerdings noch einen weiteren interessanten Link. Nämlich zur Microsoft Anti-Cross Site Scripting Library V3.0 Beta.
Beides sollte man sich wohl einmal anschauen, wenn man sich – oder seine Software
– vor entsprechenden Attacken schützen will.
Ich hoffe ich finde die Zeit dazu.
Bis bald
Kostja

Der heutige btb-Post handelt soll sich etwas intensiver mit dem Thema "nullable value types" beschäftigen:
Das .NET-Framework unterscheidet zwischen 2 verschiedenen Arten von Typen - Wertetypen und Referenztypen. Während Referenztypen null werden, wenn ihnen kein Objekt zugewiesen wurde, haben Wertetypen diese Fähigkeit nicht. Diese werden bei ihrer Initialisierung direkt mit einem Wert belegt - false bei System.Boolean oder 0 bei System.Int32. Besonders bei der Arbeit mit Datenbanken - wo ein NULL (oder in .NET-Sprache DBNull) für einen nicht gesetzen Wert bei jeder Art von Typ exisitiert, kamen Entwickler immer wieder in Schwierigkeiten: Welcher Wert soll Null repräsentieren - ist es der Standard- der Minimal- oder der Maximalwert? Und was ist wenn dieser Wert mal wirklich ein gültiger Wert ist? Es ist also durchaus notwendig zwischen "0 weil nicht gesetzt" und "0 weil 0 gesetzt wurde" zu unterscheiden. Aus dieser Notwendigkeit heraus wurde die Struktur Nullable<T> geboren. Diese Struktur kann den zugrundeliegenden Wertetypen und ebenso auch Null-Werte beinhalten. Zur Arbeit mit dieser Struktur stehen 2 grundlegende Eigenschaften zur Verfügung: HasValue gibt zurück, ob ein Wert gesetzt wurde (true) oder ob null gespeichert ist (false); Value gibt den gespeicherten Wert zurück oder wirft eine InvalidOperationException, falls versucht wird auf Value zuzugreifen und null vorliegt.
Die Deklaration ist recht einfach - entweder man deklariert eine Nullable<T>-Struktur oder man verwendet den ?-Zugriffsmodifizierer:
Ebenso einfach ist der Umgang mit Nullable<T>:
int? a = null;
if (a.HasValue)
{
Console.WriteLine("Wert: {0}", a.Value);
}
else
{
Console.WriteLine("kein Wert");
}
Natürlich können auch direkte Vergleiche mit null durchgeführt werden:
bool? a = null;
// returns the value of a or false if set to null
bool b = (a ?? false);
// returns whether a is null or not
bool c = (a == null);
In der aktuellen Ausgabe der Visual Studio One findet sich mein neuester Artikel Validierung unter WPF.
Intuitive Anwendungen weisen den Benutzer auf Fehleingaben hin. Idealerweise geschieht dies direkt in der UI, frühzeitig, ohne lange Wartezeiten. Zusätzlich ist es notwendig, Daten in der Businesslogik auf Korrektheit und Vollständigkeit zu prüfen. Norbert Eder diskutiert die Validierungsmöglichkeiten im Rahmen der Windows Presentation Foundation.
Weitere Informationen finden sich auf der Homepage von Visual Studio One.
Ich wollte auf eine Aktion aufmerksam
machen, bei der man nicht nur tolle Preise gewinnen kann, sondern auch noch etwas
für seine eigen Webseite tun kann.
Denn: Besser
für alle ist ein Web, das auf Standards basiert.
Das wollen wir von der Developer
Platform and Strategy Group der Microsoft
Deutschland GmbH unterstützen. Und Ihr könnt uns dabei helfen. Indem Ihr uns Webseiten
mitteilen, die in der Internet
Explorer 8-Standardansicht nicht korrekt angezeigt werden oder nicht funktionieren.
Wir kümmern uns darum.
Weiterführende Links:
Folge
uns auf Twitter | Bisher
gemeldete Webseiten und TOP-Teilnehmer | MSDN
Internet Explorer Developer Center
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
genau
wie Thomas, Norbert, Damir und Robert erreichte
mich heute eine sehr freudige Nachricht von Microsoft.
Ich wurde zum MVP zum
Thema ASP/ASP.NET ernannt.
Zitat:
Diese Auszeichnung wird an herausragende, führende Mitglieder der technischen
Communities verliehen, die ihre wertvollen praktischen Erfahrungen mit anderen Menschen
teilen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen
Communities zum Thema ASP/ASP.NET im vergangenen Jahr hoch ein.
Ich freue mich sehr über die Auszeichnung und danke der gesamten .NET Community! 
Die in Windows 7 eingeführten Libraries haben mich vom ersten Moment an begeistert:

Libraries erlauben es, mehrere Ordner zu einer logischen Einheit zusammenzufassen – bei mir sind in der Library “Development” z.B. sämtlicher Code, Dokumente (Docs) und Projekte (Projects) zusammengefasst.
Da ich diese Library sehr häufig verwende, habe ich mir diese in der Taskbar von Winodws abgelegt – allerdings ging das nicht ohne Umwege.
Wenn man eine exe-Datei rechtsklickt, hat man die Möglichkeit, diese direkt in die Taskbar zu docken:
Leider besteht diese Möglichkeit bei Ordnern und Libraries nicht.
Deshalb erstellt man sich zunächst z.B. auf dem Desktop eine neue Textdatei und benennt diese so um, wie die Library auf der Deskbar später heißen soll – mit dem Zusatz “.exe”:
Diese kann man nun über den oben gezeigten Rechtsklick an die Taskbar pinnen:
Allerdings startet ein Klick auf das Icon nun die vermeintliche exe-Datei und das Icon könnte auch aussagekräftiger sein…
Um dies zu ändern, hilft ein Rechtsklick auf das Symbol in der Taskbar und anschließend die Auswahl der Dateieigenschaften:
Um die die Verknüpfung zur exe-Datei zu lösen und durch den Aufruf der Library zu ersetzen, muß im Reiter “Shortcut” das “Target" durch den Pfad zu Library ersetzt werden.
Libraries werden in Windows 7 unter
C:\Users\%Username%\AppData\Roaming\Microsoft\Windows\Libraries
abgelegt.
Außerdem haben Libraries die Extension “.library-ms”, somit wäre der Pfad zu MyDockedLibrary
C:\Users\%Username%\AppData\Roaming\Microsoft\Windows\Libraries\MyDockedLibrary.library-ms
Das Icon kann man wie gewohnt über “Change Icon” anpassen.
Nach einem Klick auf OK muß man sich neu anmelden, damit das geänderte Icon übernommen wird:

Herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft® MVP Award 2009 verleihen zu können! Diese Auszeichnung wird an herausragende, führende Mitglieder der technischen Communities verliehen, die ihre wertvollen praktischen Erfahrungen mit anderen Menschen teilen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen Communities zum Thema Client App Dev im vergangenen Jahr hoch ein.
Ein Jahr ist rum und auch dieses Mal darf ich mich über die Verleihung des MVP Awards freuen. Dies macht Mut, so weiter zu machen und auch weiterhin mit vollem Elan, Teil dieser wunderbaren Community zu sein. Ein herzliches Dankeschön, ich fühle mich geehrt!
Heute bekam ich von Microsoft die freudige Nachricht, dass ich auch für das Jahr 2009 ASP.NET MVP bin. Ich hoffe in diesem Jahr noch einige Blogposts und HowTos schreiben zu können um vielleicht auch im nächsten Jahr wieder mit dabei zu sein. Besonders freue ich mich bereits auf das MVP Summit, dass ich auch schon dieses Jahr besuchen konnte.
Ich liebe Abkürzungen: ASP.NET MVC MVP ahoi
ShareThis
Gerade erreichte mich eine sehr erfreuliche Nachricht:
"... Sehr geehrter Herr Tomicic, herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft®
MVP Award 2009 verleihen zu können! ..."
Da freue ich mich aber auch. Vielen herzlichen Dank!
Die MVPs sind eine begeisternde Truppe von Technologie-Enthusiasten. Ich genieße
die Treffen mit den MVPs und die Diskussionen, wie zuletzt beim Software Strategy
Summit in Köln.
Und ich bin froh und fühle mich wirklich geehrt ein weiteres Jahr dazu zählen zu dürfen. Klasse!
:-)
[1] http://mvp.support.microsoft.com
Ich hatte ja hier schon etwas zu eigenen impliziten und expliziten Konvertierungen geschrieben. Dazu noch ein Nachtrag zur Konvertierungen zwischen zwei eigenen Datentypen. Wir haben wieder unseren Datentypen MyDataType:
class MyDataType
{
public string Wert { get; set; }
public static implicit operator string(MyDataType toConvert)
{ return toConvert.Wert; }
public static implicit operator MyOtherDataType(MyDataType toConvert)
{
int Converted;
if (Int32.TryParse(toConvert.Wert, out Converted))
return new MyOtherDataType() { Wert = Converted };
else
return null;
}
}
Dazu definieren wir uns einen eigenen zweiten Datentypen:
class MyOtherDataType
{
public int Wert { get; set; }
public static implicit operator MyDataType(MyOtherDataType toConvert)
{ return new MyDataType() { Wert = Convert.ToString(toConvert.Wert) }; }
public static implicit operator string(MyOtherDataType toConvert)
{
if (toConvert != null)
return Convert.ToString(toConvert.Wert);
else
return "toConvert is null";
}
}
Ich habe jetzt allerdings die Konvertierungen zu SecureString rausgenommen, und implizite Konvertierungen zwischen diesen beiden Datentypen hinzugefügt. Prinzipiell muss nach dem Keyword “operator” lediglich der Zieldatentyp angegebene werden, und als Methodenparameter der Quelldatentyp. Das kann man so vereinfachen:
public static implicit/explicit operator Zieldatentyp (Quelldatentyp pInstance) { Konvertierungsimplementation }
Die Main Methode unserer Konsolenanwendung sieht demnach dann so aus:
static void Main(string[] args)
{
MyDataType myTypeInstance = new MyDataType() { Wert = "hallo" };
Log("myTypeInstance: " + myTypeInstance);
//ist null, da "hallo" kein gültiger int ist
MyOtherDataType myOtherTypeInstance = myTypeInstance;
Log("myOtherTypeInstance nach ungültigem int in myTypeInstance: " + myOtherTypeInstance);
myTypeInstance.Wert = "10";
myOtherTypeInstance = myTypeInstance;
Log("myOtherTypeInstance nach gültigem int in myTypeInstance: " + myOtherTypeInstance);
Console.Read();
}
“Warum verwendet der jetzt nicht “string.Format” zum Logging?!” werden sich wohl einige Fragen. Die Antwort ist einfach: string.Format(”Text”, parameter) erwartet als parameter “objects”. Würden wir nun unsere Instanz “myOtherTypeInstance” übergeben, würde unsere Typumwandlung nach string nicht ausgeführt werden… :)
Damit sollte es jetzt eigentlich klar sein wie die eigene Konvertierungen direkt innerhalb eines Datentyps implementiert werden können.
Nachdem ich mich Gestern über das Thema “Ziemlich Sicheres
erkennen von SPAM” ausgelassen habe, möchte ich mich Heute, einem mindestens genau
so wichtigen Thema, der Virus Erkennung und Abwehr in E-Mails unter Verwendung der hMailServer Bordmittel
und lizenzfreien Zusatzprodukten widmen.
Wer den hMailServer einsetzt, wird die Optionen der AntiVirus Einstellungen kennen
und sicherlich werden die meisten die einfache Clamwin Integration
wählen.
-
Clamwin installieren
-
Use Clamwin aktivieren
-
Auto-detect anklicken
Fertig !
Das ist sicherlich eine gute und einfache Lösung (vor allem ist es eine akzeptable
Lösung) wenn auf dem Mail Server wenige Mails (einige Mails pro Stunde) verarbeitet
werden. Für Installationen mit höherem Traffic (> 100 Mails/Stunde) stellt diese
Installation aber ein echtes Performance Problem dar.
Clamwin benötigt wenn es durch den hMailServer aufgerufen wird um die Mails nach Viren
zu untersuchen enorm viel Ressourcen des Computers. Wenn gleichzeitig mehrere Mails
im hMailServer eintreffen, werden je nach Einstellungen mehrere Instanzen von Clamwin
aufgerufen um die Mails einer Virenprüfung zu unterziehen. Dies führt unweigerlich
dazu dass der Server mit nahezu 100% CPU Last nicht mehr viel Luft für andere Aufgaben
hat.
Es gibt aber auch hierfür eine Lizenzkostenfreie Lösung und diese arbeitet mit der
gleichen Scan Engine wie Clamwin.
ClamAV für Windows
in der Variante von SOSDG.
Stand Heute ist die aktuelle Version der SOSDG Variante die 0.95-1, diese Version
können wir aber für die Integration mit dem hMailServer “leider” nicht nehmen. Ich
hoffe aber, dass bald eine fehlerbereinigte Version folgt, die dann die aktuellste
ClamAV Engine einsetzen kann.
Um die Integration mit dem hMailServer zu realisieren müssen wir die Version clamav-0.94-2-1a.exe
herunterladen und installieren.
Nachfolgend werde ich den Installationsprozess sowie die notwendigen Einstellungen
im Detail erläutern.
Diese Anleitung basiert auf dem englischen Forumbeitrag von
“rodolfor” im hMailServer Forum.
Schritt für Schritt Anleitung, oder in 9 Schritten zu einer performanten kostengünstige
AntiVirus Lösung für hMailServer)
1. Herunterladen der clamav-0.94-2-1a Version
2. Installieren der clamav-0.94.2-1a Version
a) Setup ausführen
b) Als Installationstyp “Full auswählen (sonst werden benötigte Komponenten nicht
installiert)
c) Dann den Setup mit den Standard Werten (am besten auch im Standard Verzeichnis)
ausführen.
Zum Ende der Installation startet automatisch die Aktualisierung der Viren Signatur
Datenbank.
d) Installation abschließen
3. Konfiguration “c:\clamav-devel\etc\clamav.conf” anpassen. (Datei c:\clamav-devel\etc\clamav.conf
mit einem Texteditor öffnen)
a) LocalSocket /cygdrive/c/clamav-devel/clamd.sock in der Datei suchen (eigentlich
Zeile 82)
Diese Zeile durch das voranstellen eines # auskommentieren (siehe nachfolgende Zeile)
# LocalSocket /cygdrive/c/clamav-devel/clamd.sock
b) #TCPSocket 3310 in der Datei suchen (eigentlich Zeile 90)
In dieser Zeile das Kommentarzeichen # am Anfang entfernen (siehe nachfolgende Zeile)
TCPSocket 3310
c) Zur Aktivierung der Log Funktion (würde ich unbedingt empfehlen) folgende Einstellung
vornehmen
#LogFileUnlock yes in der Datei suchen (eigentlich Zeile 32)
In dieser Zeile das Kommentarzeichen # am Anfang der Zeile entfernen (siehe nachfolgende
Zeile)
LogFileUnlock yes
4. ClamAV (Hilfs)Dienst installieren
Hierzu öffnet man ein DOS (Kommando) Fenster.
Wechselt in das Verzeichnis C:\clamav-devel\thirdparty\runclamd
Gibt den Befehl runclamd –install ein und führt diesen aus
Wenn der Befehl erfolgreich durchgeführt wurde, gibt der Server im DOS Fenster “service
installed” zurück.
Nun schließen wir das DOS Fenster
5. ClamAV (Hilfs)Dienst einrichten und starten
In den installierten Diensten suchen wir nun den Dienst Run Clamd
Öffnen das Eigenschaften Fenster
Und stellen den Starttyp für den Dienst von Manuell auf Automatisch
Nun starten wir den Dienst (dieses mal mit der Hand) beim nächsten Start wird er Automatisch
gestartet.
6. Beheben von Zugriffproblemen der Log Datei
Wer möchte kann kann versuchen nun schon die Log Datei clamd.log im Verzeichnis C:\clamav-devel\log
zu öffnen. Es wird schnell klar dass es nicht geht. Klar wird man denken, der Dienst
greift ja darauf zu und deshalb ……
Nein das ist es nicht, wir haben übrigens in der Konfiguration Schritt 3c dem Program
gesagt, dass wir die Log Datei lesen wollen. Also das Problem liegt nicht daran dass
die Datei geöffnet ist, sondern (und da habe ich eine ganze Zeit suchen müssen) daran,
dass die Zugriffsrechte für diese Datei etwas merkwürdig gesetzt sind.
Schauen wir uns doch mal die Rechte für diese Datei an:
Ich bin übrigens als Administrator an diesem System angemeldet, und trotzdem kann
/ darf ich die Rechte hier nicht ändern.
Es gibt aber einen ganz einfachen Trick wie wir hier weiterkommen. Hierzu betätigen
wir den Button Erweitert und dort den Reiter Besitzer:
Hier sehen wir,dass der Besitzer das System ist. Das werden wir nun einfach ändern,
indem wir den Besitzer ändern auf “Administratoren".
Wenn wir nun alle Rechte Fenster geschlossen und das Fenster der Dateiberechtigungen
noch einmal öffnen:
Können wir auch das Lesen Recht für Jeden (oder wie auch immer) setzen (Und danach
auch die Log Datei öffnen).
7. ClamAV in hMailServer eintragen und aktivieren
Nun müssen wir die nachfolgenden Einstellungen im hMailServer Administrations Tool
im Bereich Anti-Virus vornehmen
Auf der Karteikarte External Virus Scanner nehmen wir folgende Einstellungen vor:
-
Use external scanner (aktivieren)
-
Im Feld Scanner executable wird "C:\clamav-devel\bin\clamdscan.exe" --no-summary --stdout
"%FILE%" eingetragen (Mit den “)
-
Im Feld Return Value wird 1 eingegeben
8. Automatische Aktualisierung der Virus Signaturen einrichten
Einrichten eines geplanten Task für die Datei C:\clamav-devel\bin\freshclam.exe. Zum
Beispiel Alle 2 Stunden
9. Tests
Zum Abschluss sollte man noch testen, ob alles einwandfrei funktioniert. Hierzu möchte
ich zwei Beispiele geben, um den Viren Scanner und die Implementierung im hMailServer
zu testen
Scanner testen
In einem geöffneten DOS Fenster gibt man die folgende Befehlszeile ein und führt sie
aus:
"C:\clamav-devel\bin\clamdscan.exe" --no-summary --stdout "C:\clamav-devel\test\clam-nsis.exe"
Wenn der Scanner richtig installiert ist wird nach dem ausführen des Befehls die folgende
Antwort im DOS Fensters zurückgegeben:
Integration testen
Um die Mail Integration zu testen schickt man ein E-Mail mit der Datei C:\clamav-devel\test\clam-nsis.exe
als Anhang an eine bekannte (eigene) E-Mail Adresse.
Wenn die Integration erfolgreich war, dann solle der Anhang von ClamAV über den hMailServer
herausgefiltert werden.
Nachdem die beiden Tests durchgeführt sind, sollte man noch das Protokoll C:\clamav-devel\log\clamd.log
anschauen. Dort sollten auf jeden Fall Protokolleinträge für die beiden Test aufzufinden
sein.
Habe grad ein paar Postings zum Thema Distributed Domain Driven Design (DDDD oder “D4”?) gelesen. Dabei ist mir wieder der Gedanke gekommen, dass wir uns das Leben noch schwerer machen als nötig. Ich glaube nämlich, zu unserem Glück fehlt uns noch eine deutliche Separation of Concerns (SoC). Über das DataSet kann man sagen, was man will, es hat eins ganz wunderbar getan: Änderungen verfolgen.
Am 13. Oktober 2008 haben Peter Bucher und ich unter dem Titel Noch Fragen, Bucher? Ja, Roden! angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen. Bisher sind in dieser Reihe folgende Kommentare erschienen:
Heute, am 1. Juli 2009, ist es nun wieder so weit, und unser Thema für diesen Monat lautet:
Primärschlüssel: GUID vs Identity
So wohl Peter wie auch ich haben uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. Peters Kommentar findet sich zeitgleich in seinem Blog, folgend nun mein Kommentar zu diesem Thema:
Die Aufgabe, eine Datenbankstruktur zu entwickeln, ist nicht leicht. Auf der einen Seite ist in der Regel eine möglichst hohe Normalisierung gewünscht, auf der anderen Seite darf die Performance nicht unter einer Vielzahl von Joins leiden.
Aus diesem Grund trifft man die fünfte Normalform – so wünschenswert ihre Umsetzung in der Theorie auch sein mag – in der Praxis nur ausgesprochen selten an: Der in der Datenbank notwendige Aufwand zur Bearbeitung einer Abfrage ist schlichtweg zu hoch.
In der Praxis trifft man daher zumeist auf Strukturen, die sich zwischen dritter, vierter und der sogenannten Boyce-Codd-Normalform bewegen. Essenziell ist in allen Fällen jedoch die Wahl eines geeigneten Primärschlüssels.
Ein Schlüssel ist dabei wie folgt definiert:
- Ein Superschlüssel ist eine Menge von Feldern einer Tabelle, deren Zusammenspiel einen Datensatz eindeutig identifizieren. Beispielsweise könnte in vielen Fällen die Kombination aus Name, Vorname, Geburtsdatum und Adresse als Superschlüssel dienen, da es ausgesprochen unwahrscheinlich ist, dass zwei Personen gleichen Namens am gleichen Tag geboren sind und zudem noch an der gleichen Adresse wohnhaft sind.
- Als Schlüsselkandidat bezeichnet man alle Superschlüssel, bei denen die Anzahl der verwendeten Felder minimal sind. Angenommen, beim vorigen Beispiel ließe sich das Geburtsdatum entfernen, ohne zugleich die Eindeutigkeit zu verlieren, dann wäre auch die Kombination aus Name, Vorname und Adresse ein Superschlüssel. Diese Version verwendet jedoch ein Feld weniger als die vorige. Sobald kein Feld mehr entfernt werden kann, ohne die Eindeutigkeit zu verlieren, spricht man von einem Schlüsselkandidaten.
- Der Primärschlüssel ist schließlich ein (willkürlich) ausgewählter Schlüsselkandidat, der als Hauptidentifikationsmerkmal dient.
Eine interessante Frage ist, wie ein solcher Primärschlüssel aussehen sollte. Prinzipiell gibt es hierzu zwei Möglichkeiten: Entweder verwendet man lediglich Felder, die ohnehin als Bestandteil der Daten vorhanden sind – in diesem Fall nennt man den Schlüssel einen natürlichen Schlüssel, da alle enthaltenen Felder auch über eine natürliche Bedeutung in den Daten verfügen.
Oder man verwendet ein dediziertes, künstlich hinzugefügtes Feld, das zwar keine semantische Beziehung zu den Daten aufweist, dafür allerdings auf den Einsatz als Schlüssel optimiert wurde – in diesem Fall spricht man von einem Surrogatschlüssel.
Die Vorteile von Surrogatschlüsseln liegen auf der Hand: Da bei natürlichen Schlüsseln gegebenenfalls mehrere Felder zu einem Verbundschlüssel zusammengefasst werden müssen, ist die Arbeit mit ihnen arbeits- und zeitaufwändig. Surrogatschlüssel hingegen können auf das jeweilige Einsatzgebiet optimiert werden.
Die Frage lautet also: Wie sollte ein Surrogatschlüssel aussehen?
In der Praxis haben sich hierzu zwei Ansätze etabliert. Das erste Verfahren verwendet einen nummerischen Schlüssel, der im Regelfall durch die Datenbank hochgezählt und automatisch vergeben wird. Das zweite Verfahren nutzt sogenannte GUIDs – global eindeutige IDs.
Historisch bedingt sind nummerische Schlüssel wesentlich stärker verbreitet als GUIDs. Zudem verfügen GUIDs über einige immanente Nachteile:
- Eine GUID belegt 16 Byte in der Datenbank, ein int hingegen nur 4 Byte. Abgesehen von dem zusätzlichen Speicherbedarf, der durch die Verwendung von GUIDs erzeugt wird, sind GUIDs aus diesem Grund auch nicht so performant wie int-Felder: Ein Vergleich auf 16 Bytes dauert logischerweise länger als ein Vergleich auf 4 Bytes.
- Eine GUID ist schlechter lesbar als ein int. Das macht sich insbesondere beim Debuggen und bei der Fehlersuche bemerkbar.
- Verschiedene GUIDs implizieren im Gegensatz zu fortlaufend vergebenen int-Werten keine Reihenfolge, sodass nicht nur eine natürliche Sortierung fehlt, sondern auch die Clusteringfähigkeit der Datenbank leidet.
Doch wo Schatten ist, ist auch Licht:
- Eine GUID ist garantiert eindeutig – nicht nur in der Tabelle, sondern auch in Bezug auf die gesamte Datenbank und andere (!) Datenbanken. Das bedeutet, dass das Mergen von Datenbanken problemlos möglich ist, da es zu keinen Konflikten von Primärschlüsseln kommt, wie dies bei int-Werten häufig der Fall ist. Auch die Replikation von Datenbanken erfordert in der Regel die Verwendung von GUIDs – andernfalls wäre die Konsequenz ein äußerst aufwändiges Nachziehen von zu ändernden int-Werten.
- Eine GUID kann vom Client erzeugt werden, der nächsthöhere int-Wert muss durch den Server erzeugt werden. Dies bedeutet im schlechtesten Fall, dass nach dem Einfügen eines Datensatzes ein weiterer Roundtrip zum Server nötig ist, um den erzeugten Schlüssel zu erhalten. Hierbei tritt bei der Verwendung von int-Werten häufig auch das Problem auf, wie mit nahezu zeitgleich eingefügten Datensätzen umgegangen wird – die Schlüssel müssen verbindungsbezogen zurückgegeben werden.
Ein besonderes Feature, das zwar nicht auf der Verwendung von GUIDs basiert, aber eindrucksvoll beweist, wie nützlich ein datenbankweit eindeutiger Schlüssel ist, enthält die Datenbank PostgreSQL: Die sogenannte OID (Object ID) ist ein automatisch von PostgreSQL vergebener eindeutiger Schlüssel, der in allen Datenbanken auf dem verwendeten Server eindeutig ist.
Die Besonderheit in PostgreSQL liegt nun darin, dass diese OID in Abfragen verwendet werden kann, um auf Datensätze zuzugreifen, ohne zu wissen, in welcher konkreten Datenbank oder Tabelle diese enthalten sind.
Aus all diesen Überlegungen kann als Fazit gezogen werden, dass die Verwendung von GUIDs generell empfohlen werden kann: Die genannten Vorteile überwiegen die wenigen Nachteile bei weitem, insbesondere auch im Hinblick auf die Zukunftssicherheit: Eine Datenbank, die ohnehin GUIDs verwendet, lässt sich ohne weiteres replizieren – eine Datenbank, die auf int-Werten basiert, nicht.
Als einzige Ausnahme dieser Regel sei der Fall genannt, wenn es auf das noch so kleinste Quentchen Performance ankommt: In diesem Fall sind int-Werte eventuell eine Option – allerdings stellt sich dann ohnehin die Frage, ob die Datenbank nicht per Scale-up oder Scale-out anders aufgebaut werden sollte.
Manchmal sind es die trivialsten Dinge, die vergessen werden. Statt einen Knoten ins Taschentuch zu machen, mach ich mir hier eine Notiz:
„Wo habe ich nur den Schlüssel hingelegt?“ .
In den Kühlschrank.
Wie kann ich eine SQL-Datenbank für die Userverwaltung einrichten
aspnet_regsql.exe
Wo finde ich das Unit-Test-Framework für Silverlight?
Das Unit-Test-Framework ist in der MSDN unter http://code.msdn.microsoft.com/silverlightut/ zu finden.
This test framework is a solution built by developers, for developers, to help get a jump start on building richer applications and components for Microsoft Silverlight 2. The framework is currently available as a binary download for use in your own applications.
Wo ist der Sourcecode für das Unit-Test-Framework?
Der Sourcecode des Unit Test Framework for Microsoft Silverlight 2 ist im Silverlight Toolkit http://www.codeplex.com/Silverlight/
Funktioniert das Unit-Test-Framework für Silverlight auch für Silverlight 3
Ja.
Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Golo? Ja, Bucher! angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen. Bisher sind in dieser Reihe folgende Kommentare erschienen:
Heute, am 1. Juli 2009, ist es nun wieder so weit, und unser Thema für diesen Monat lautet:
Primärschlüssel: GUID vs Identity
So wohl Golo wie auch ich haben uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. Golos Kommentar findet sich zeitgleich in seinem Blog, folgend nun mein Kommentar zu diesem Thema:
In letzter Zeit scheint es immer mehr aufzukommen, GUIDs anstelle von Integers als Primärschlüssel zu benutzen.
Dieser Blogeintrag soll bei der Entscheidung helfen, die mir bekannten und recherchierten Vor- und Nachteile hervorheben und meine persönliche Meinung kundgeben.
Kurz und schmerzlos Vor- und Nachteile:
Guid Vorteile:
- Der Schlüssel kann unabhängig vom Datenbanksystems vergeben werden.
- Einzigartigkeit des Schlüssels über jede Tabelle, Datenbank und sogar Server gewährleistet.
- Das Zusammenführen von Datenbanken ist ohne Änderung der IDs einfach möglich.
- Unbegrenzte Anzahl an IDs, keine Beschränkung auf den Datentyp wie bspw. int.
Guid Nachteile:
- Braucht 4 Mal mehr Platz als ein Integer.
- Dadurch und je nach Aufgabe und Server kann die Performance der Datenbank leiden.
- Schlecht lesbar und zu merken, bspw. auffallend beim Debugging.
- Keine nachvollziehbare, chronologische Reihenfolge der IDs.
- Nicht von allen Plattformen nativ unterstützt.
Identity Vorteile:
- 4 Mal geringerer Platzbedarf als eine Guid.
- Kann je nach Situation eine bessere Performance im Gegensatz zu Guids liefern.
- Gut lesbar und zu merken.
- Chronologische Reihenfolge der IDs.
Identity Nachteile:
- Der Schlüssel kann nur vom Datenbanksystem vergeben werden.
- Einzigartigkeit der Schlüssel ist nur innerhalb einer Tabelle gewährleistet, was beim Zusammenführen von Datenbanken unweigerlich zu Problemen führt.
- Durch Datentyp begrenzte Anzahl von verfügbaren Schlüsseln für eine Tabelle.
- Durch Löschen von Datensätzen oder RollBacks entstehen Lücken zwischen den sonst chronologischen IDs.
Mit der Nutzung von GUIDs ist es möglich den / die Schlüssel unabhängig vom Datenbanksystem zu vergeben, das ist bspw. nützlich bei Anwendungen die auch im Offline-Modus laufen können.
Wenn mehrere Tabellen mit Identity-Schlüsseln zusammengeführt werden, müssen die IDs zwangsläufig ändern, da sie nur innerhalb einer Tabelle einzigartig sind. Das führt beispielsweise dazu das Links oder irgendwelche gespeicherten Lesezeichen innerhalb einer Applikation nicht mehr gültig sind.
Ein interessanter Vorteil beim verwenden von GUIDs lässt sich aus der Tatsache erzielen, das die IDs auf über mehrere Tabellen (Auch Datenbanken und Server) einzigartig sind.
Dadurch ist es bspw. möglich eine Tabelle anzulegen, die Zusatzdaten wie bspw. für die Lokalisierung enthält, die auf jede unserer anderer Tabellen zutreffen könnten.
Die Tabelle hat eine Primärschlüssel-Spalte und eine GUID-Spalte als Fremdschlüssel auf einen Datensatz irgend einer Tabelle.
Bei einer Abfrage oder dem Speichern brauchen wir nur die GUID des aktuellen Datensatzes und keine Zusätzlichen Angaben mehr, wie bspw. den die Tabelle zu dem der Datensatz gehört, da es eben nicht Nummern sind die auch in anderen Tabellen vorkommen können.
Für kleine Anwendungen, bspw. im Zusammenspiel von XML als Datenquelle nutze ich immer GUIDs. Die Verwaltung von Identity-Schlüsseln wäre mir da zu aufwändig und dessen Vorteile benötige ich dort gar nicht.
Bei bestehenden Projekten an denen ich mitarbeite wird meistens Identity als Schlüssel verwendet, ausser man benötigt einer der Vorteile von GUIDs.
Ich schimpfe mich bewusst nicht zum Experten was Datenbanken angeht und bin daher gespannt auf die Meinungen aus der Community und von Golo.
OK - das ist wirklich eine interessante
Fragestellung fällt mir gerade auf. Gibt es sowas? Wie dem auch sei, ich könnte mir
insbesondere beim Thema "Fehlerbehebung" oder "Fehlersuche" in einem Auto sehr gut
vorstellen, dass man hier etwas mit DeepZoom, Silverlight und
Co. machen könnte. Z.B. so etwas wie: Du musst Stecker A auf B stecken um Stecker
C dann anschließend in die Buchse D einzuführen. Dabei ziehe Klappe 124 heraus und
achte darauf, Steckverbindung 27C nicht zu berühren. Man kennt doch diese Bücher: "So
wird's gemacht"-Bücher
Ich könnte mir sehr gut vorstellen,
dass man hier ansetzen könnte, oder?
Wie bin ich darauf gekommen, ich habe
mir Seiten wie Audi
A4 allroad: Zoomen Sie sich rein, BMW
Z4: Zoomen Sie sich rein! oder den Mazda
Konfigurator angeschaut.
Dann bin ich ein wenig gesurft und
habe geschaut, gibt es so etwas überhaupt schon - so eine interaktive zooooming Fehleranleitung
in Autos integriert? Gefunden habe ich nichts, aber wenn man sich mal Damirs Blogposting
'Introducing
SILVERHD' liest man, welche Möglichkeiten es hier überhaupt gibt. Interessant
nebenher gesagt ist, dass man nicht nur auf http://silverhd.net ein
bzw. mehrere interessante Anwendungsbeispiele findet, wer den Twitter-Account SilverHDNet verfolgt,
findet die eine oder andere interessante Idee - ist sehr dynamisch der Twitter-Account,
wie ich finde.
Viele Ideen
-
da lässt sich was machen!
Weiterführende Links:
This post is powered by www.Giza-Blog.de |
Visit: MSDN
Online | Kostenfreie
MSDN Service-Hotline für Entwickler
Daily News on MSDN: MSDN
Aktuell
© Copyright
2006-2009 Kay Giza. All rights reserved. Legal
Letzte Woche fand ja die ASP Konferenz – das Sharepoint Development Special in Burghausen statt. Ich hatte das Vergnügen 4 Vorträge zur Sharepoint Entwicklung abzuhalten. Die Demos und Slides der recht kurzen Sessions sind ab nun hier verfügbar:
Bei Fragen, Wünschen etc. bin ich jederzeit per Mail erreichbar.
Seit einigen Tagen ist es wieder soweit, die Registrierung zur NRW Conf 09 ist online.
Wie schon in den vergangenen Jahren treffen sich am 28.08.2009 auf diesem größten Community Event in NRW wieder Entwickler, IT-Pros und UI-Designer aus ganz Deutschland, um sich einen ganzen Tag lang zu informieren und auszutauschen. Mit diesmal 35 Vorträgen in 4 parallelen Tracks ist die Konferenz dabei so groß wie noch nie. Die teils internationalen Referenten bieten wieder einen spannenden Mix aus Themen rund um die Softwareentwicklung. Hier geht’s zur Agenda.
Zum ersten Mal gibt es in diesem Jahr am Tag vor der Hauptkonferenz einen Workshop Day. Für jeweils maximal 8 Teilnehmer gibt es zwei Themen zur Auswahl: Microsoft Exchange 2010 und Microsoft Web Platform.
Nichts geändert hat sich bei der Teilnahmegebühr und dem Veranstaltungsort. Die Registrierung kostet wieder 15 EUR und der Veranstaltungsort ist wie in den letzten beiden Jahren “die boerse” in Wuppertal.
Mein Thema in diesem Jahr: “Data Driven RIAs mit Silverlight”.
Ich freue mich auf viele bekannte – aber auch auf neue – Gesichter, eine tolle Community Veranstaltung und interessante Gespräche.
Ciao Kostja

Ich habe seit vielen Jahren den hMailServer in
verschiedenen Installationen, sowohl als eigenständigen E-Mail Server als auch im
Zusammenspiel (als ESMTP Server) mit MS Exchange Server, im Einsatz. In kleinen und
mittleren Betrieben ist hMailServer sicherlich eine günstige (da Lizenzkostenfrei)
alternative zu einem hochpreisigen Produkt wie dem Microsoft Exchange Server. Vor
allem dann, wenn es hauptsächlich um E-Mail geht und die Groupware Funktionen eines
Exchange Server nicht benötigt werden.
Wobei ich gleich hier erwähnen möchte, dass die hier beschriebene
Version des hMailServer über IMAP nun auch öffentlichen Ordner zur Verfügung stellt.
Nun aber zum eigentlichen Thema dieses Beitrags,:
“Ziemlich” Sicheres erkennen von SPAM !!!
In der heutigen Zeit ist das Thema SPAM so aktuell wie noch nie.
Ich persönlich erhalte täglich zwischen 300 und 1000 SPAM Mails (Das liegt sicherlich
auch daran, dass ich schon seit über 20 Jahren mit teilweise den gleichen E-Mail Adressen
arbeite).
Auch wenn es mittlerweile sehr gute SPAM Filter gibt, so kann man doch meistens die
als SPAM erkannten Mails nicht einfach löschen, da hier und da doch einmal ein E-Mail
welches man benötigt vom SPAM Filter als SPAM erkannt wird.
Was bleibt ist, die SPAM Mails in einen Ordner umzuleiten und diese bevor man sie
löscht zu überfliegen um die eine oder andere “normale” Mail auszusortieren bevor
man die “richtigen” SPAM Mails löscht.
Wenn man nun aber, wie ich bis zu 1000 SPAM Mails am Tag erhält, dann ist das fast
ein Tagfüllender Job, vor allem dann, wenn man E-Mails zeitnahe bearbeitet.
Wenn man doch nur mehr Zuverlässigkeit in der Erkennung der SPAM Filter erreichen
könnte !!!
Man kann !! (wenn man den hMailServer einsetzt)
Und das ganze auch noch vollkommen ohne zusätzliche Kosten mit den Bordmitteln von
hMailServer, ohne zusätzliche Installation eines weiteren SPAM Filters wie Beispielsweise SpamAssassin.
Nun aber zur Theorie und der Praxis:
Der in hMailServer integrierte SPAM Filter besteht aus mehreren Komponenten:
Zuerst sind sind das die “einfachen” SPAM Test varianten:
-
Verwendung SPF (nicht
sehr aussagekräftig da noch viele dieses Feature nicht nutzen)
-
HELO Prüfung
(lest selber wie zuverlässig diese Prüfung ist)
-
DNS-MX Record
(eigentlich sollte den jeder haben, aber auch hier würde ich nicht sehr viel Aussagekraft
bescheinigen)
-
DKIM-Signatur (meiner
Meinung nach noch nicht verbreitet genug um aussagekräftig zu sein)
Auch wenn diese einfachen SPAM Test verfahren im einzelnen nicht sehr viel Aussagekraft
haben, so kann doch das auftreten mehrerer dieser Testergebnisse ein zusätzliches
Merkmal zur Erkennung von “echter” SPAM sein.
Wie man schon auf der obigen Abbildung erkennen kann ist jedem der Testverfahren ein
Score zugeordnet. Dieser Score wird noch eine entscheidende Rollen in diesem Beitrag
spielen. Mehr dazu später.
Nu gibt es außer den einfachen Tests noch weitere SPAM Erkennungsverfahren:
Neben den für diesen Beitrag nicht relevanten Verfahren des Grey- und Whitelisting
widmen wir den beiden SPAM Erkennungsverfahren die für diese Beitrag relevant sind:
DNS Blacklist
DNS Blacklist Server sind im Prinzip Server die Listen von IP Adressen enthalten die
als Herkunft von zweifelhaften Mails bekannt sind.
Man kann unter hMailServer mehrere solcher DNS Blacklisten einrichten.
Ich habe hier die beiden oben dargestellten Blacklist Server eingerichtet.
Man kann bei jedem der Blacklist Server wieder einen Score vergeben (mehr dazu später):
SURBL Server
Wie bei den DNS Blacklisten kann man bei den SURBL Servern auch mehrere einrichten.
Wie aus der nachfolgenden Abbildung zu sehen ist, begnüge ich mich mit einem:
Und wen wundert es, wenn ich sage, man kann jedem SURBL Server wiederum einen Score
zuweisen kann.
Nun möchte ich nicht auf die Arbeitsweisen der einzelnen SPAM Prüfverfahren eingehen,
dafür kann man die Links verwenden und von Menschen die wirklich was davon verstehen
die Einzelheiten zu den einzelnen Verfahren nachlesen.
Jetzt aber endlich zum Thema “SPAM score” auf das ich im gesamten Verlauf des Beitrags
schon mehrfach hingewiesen habe.
Auf der Einstiegsseite des Anti Spam Konfiguration des hMailServer finden wir unter
anderem den folgenden Eintrag:
Die einzelnen Testverfahren besitzen jeweils einen score, der von hMailServer beim
durchlaufen der SPAM Filter zu einem Wert (dieses SPAM mark treshold) addiert werden.
Erst wenn die Summe der Score aus den einzelnen Testverfahren diesen Schwellwert (hier
sind es 5) übersteigen wird die Mail als SPAM gekennzeichnet.
Unabhängig dieser Kennzeichnung wird aber der Score (Summe aller SPAM Score der Prüfverfahren
welche die Mail als SPAM identifiziert haben) auch als X-Header in das E-Mail eingefügt.
Dieser X-Header lautet: X-hMailServer-Reason-Score
Dieses Header kann man mit den meisten E-Mail Programmen aber auch direkt mit dem
Regelassistent des hMailServer abfragen.
Und genau hierdurch haben wir eine einfache Möglichkeit mit hoher Genauigkeit SPAM
Mails erkennen zu können..
Am besten veranschauliche ich das an einem Beispiel:
Eine eingehende Mail wird von hMailServer empfangen und wird durch die “einfachen”
SPAM Tests durchlaufen.
Daraus resultiert ein SPAM core von 2 weil kein die HELO Prüfung fehlgeschlagen ist.
Nun wird der DSN Blacklist Test durchlaufen und auf dem Server bl.soamcop.net wird
die IP Adresse des Absender gelistet, dadurch wird der Score um 3 erhöht. Somit ist
der SPAM score nun 5.
Als nächstes erfolgt der SURBL SPAM Test und auch dort wird der Mail Inhalt als mögliche
SPAM Mail erkannt was den SPAM core noch einmal um 3 erhöht. Das bedeutet der SPAM
core ist nun 8.
Nun, da ich ein Kriterium an der Hand habe um “sichere” SPAM Mails von “eventuellen”
SPAM Mails unterscheiden zu können kann ich ein weiteres Feature des hMailServer verwenden
um Mails mit einem SPAM Core > X direkt zu löschen.
Dies kann ich, mit dem ebenfalls im hMailServer direkt enthaltenen Regelassistenten,
welcher unter dem jeweiligen Account des Benutzer (Im Administrationstools zu finde
ist, einfach bewerkstelligen.
Hier richte ich eine neue Regel mit den nachfolgenden Kriterien ein:
Bei den Aktionen wird Delete E-Mail ausgewählt.
Ich habe zusätzlich noch ein “Stop Rule Processing” verwendet, damit nach dem löschen
der Mail nicht noch versucht wird weitere Regeln zu durchlaufen. (Ist ja keine Mail
mehr vorhanden
)
Nach diesem Prinzip kann man natürlich ohne Grenzen andere Regeln definieren, wie
das verschieben von Mails in einen speziellen IMAP Ordner die manuell geprüft werden
müssen usw.
Die X-Header die von hMailServer eingefügt werden können alternativ auch von Mail
Clients (z.B. Thunderbird,
Outlook usw.) zur Ausführung von lokalen Regeln und Skripten verwendet werden.
Übrigens: Die hier beschriebenen Feature sind enthalten im hMailServer
Version 5.1.2
Dank des Feedbacks in den beiden vorherigen Artikeln, und im speziellen die Kommentare von winSharp93 im vorangegangenen Beitrag, habe ich nun endlich eine saubere Lösung gefunden. Manchmal muss man halt mit der Nase darauf gestoßen werden. Object.ReferenceEquals ist der perfekte Weg um die Instanzen zweier Objekte zu vergleichen; sagt ja auch der Name der Methode.
Der Fehler den ich von Anfang an beging, war schlicht und einfach das Vergessen der Instanz Prüfung, nach dem ich die Equals-Methoden sowie die Operatoren == und != überschrieben hatte. Man kann nun mal nicht den Inhalt zweier Klassen vergleichen, wenn eine oder beide einen null-Verweis besitzen. Also muss in der Methode Equals(T other) als erstes eine Prüfung gegen null des other-Parameters her. Sollte hier true zurückgegeben werden, wird die aktuelle Instanz, also this, ebenfalls gegen null geprüft. Es könnten ja zwei null-Instanzen des Typs miteinander verglichen werden, was durchaus legitim ist. In diesem Fall muss die Methode Equals true zurück geben, da null == null nun mal true ergibt. Als nächstes wird noch einmal die aktuelle Instanz separat gegen null geprüft, denn sie könnte null sein und der other-Parameter eine erzeugte Instanz enthalten. Als letzten werden dann noch die Inhalte der Eigenschaften im einzelnen verglichen.
namespace ClassTests
{
using System;
public sealed class Test : IComparable<Test>
{
public int Number
{ get; set; }
public string Text
{ get; set; }
public Test()
{
}
public int CompareTo(Test other)
{
return this.Number.CompareTo(other.Number);
}
public static bool operator ==(Test t1, Test t2)
{
return object.Equals(t1, t2);
}
public static bool operator !=(Test t1, Test t2)
{
return !object.Equals(t1, t2);
}
public static bool operator >(Test t1, Test t2)
{
return (t1.CompareTo(t2) > 0);
}
public static bool operator <(Test t1, Test t2)
{
return (t1.CompareTo(t2) < 0);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Test);
}
public bool Equals(Test other)
{
if (object.ReferenceEquals(other, null))
{
if (object.ReferenceEquals(this, null))
{
return true;
}
return false;
}
if (object.ReferenceEquals(this, null))
{
return false;
}
if (this.Number.CompareTo(other.Number) != 0)
{
return false;
}
if (string.Compare(this.Text, other.Text, StringComparison.Ordinal) != 0)
{
return false;
}
return true;
}
}
}
Mit dieser Implementierung ist das Verhalten nun endlich so, wie es von Anfang an sein sollte; Instanz Prüfung, Inhaltsprüfung und Größenvergleich.
Ich möchte mich hier auch noch einmal bei allen Kommentierenden, besonders bei winSharp93, bedanken. Ohne euch würde ich wahrscheinlich noch immer grübeln.
Proxy Switcher arbeitet derzeit mit dem Internet Explorer und Firefox zusammen. In
der Regel greifen Anwendungen automatisch auf die Proxy Einstellungen des Internet
Explorers zurück, weshalb es normalerweise vollkommen ausreichend ist.
Hat man nun aber einen Sonderfall, also eine Applikation die nicht auf die Internet
Explorer settings zurückgreifen kann, benötigt man ein zusätzlichen “Switcher”.
In diesem Artikel zeige ich, wie einfach es ist, selbst einen zu entwickeln und im
Proxy Switcher zu verwenden.
Implementierung
Zunächst erstellt man ein neues Class Library Projekt im Visual Studio 2008. Dies
ist auch mit der kostenlosen Variante Visual
Studio 2008 Express (C# oder VB.NET) ohne Probleme möglich.
Als nächstes fügt man eine Referenz auf ProxySwitcher.Shared.dll hinzu. Dort befindet
sich die benötigte Basisklasse.
Nun noch die Class1.cs Datei umbenennen, z.B. in DemoSwitcher.cs. Dadurch wird auch
automatisch die Klasse umbenannt. Diese Klasse muss nun von der SwitcherBase Klasse
erben, wofür außerdem das using statement hinzugefügt werden muss:
Über das SmartTag was erscheint wenn man SwitcherBase ausgeschrieben hat, lassen sich
automatisch alle benötigten Methoden erzeugen. Das wären “DisableProxy”, “EnableProxy”
und die Eigenschaft “Name”.
Über die Name Eigenschaft kann man einen Namen vergeben, der später dann im Proxy
Switcher angezeigt wird.
Enable und Disable sollte sich von selbst erklären. Innerhalb der Methoden kann man
auf this.CurrentProxyEntry zugreifen um die Daten abzurufen, die nun aktiviert/deaktiviert
werden sollen.
Damit hätten wir die minimal Implementierung beendet.
Erweiterte Funktionen
Man kann nun noch für seinen Switcher Einstellungen laden und speichern und auch einen
Settings Dialog als Windows Form anbieten (wofür dann noch eine Referenz auf “System.Windows.Forms”
hinzugefügt werden muss):
Deployment
Nachdem man alles soweit fertig hat, muss das Projekt noch kompiliert werden. Dadurch
entsteht eine DLL, in meinem Fall PSDemoSwitcher.dll.
Diese muss nur noch in das Verzeichnis kopiert werden, wo auch ProxySwitcher.exe liegt.
Also normalerweise “C:\Programme\ProxySwitcher”.
Startet man nun den ProxySwitcher, erscheint im ersten Tab direkt mein neuer Switcher
und kann selektiert werden, damit er auch aufgerufen wird.
Update:
Die dokumentierte Beispielimplementierung gibt es hier
zum download.
Zuletzt in: