Blog Home  Home Feed your aggregator (RSS 2.0)  
HP's Blog - ProgrammierungCode
Hans-Peter Schelian's Weblog
 
# Monday, March 15, 2010

Einige meiner Tools (darunter vor allem eine Monitorprogramm zur Überwachung von Windows Diensten auf Basis eines UDP TraceListener) funktionieren unter Windows 7 nicht mehr korrekt.

Besser gesagt, beim versucht die lokale IP Adresse zu ermitteln tritt folgender Fehler auf:

{System.Net.Sockets.SocketException: Es wurde eine Adresse verwendet, die mit dem angeforderten Protokoll nicht kompatibel ist
   bei System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   bei System.Net.Sockets.Socket.Bind(EndPoint localEP)

 

Der nachfolgende Code Ausschnitt hat unter Windows XP noch einwandfrei funktioniert:

HostIP = Dns.GetHostAddresses(Dns.GetHostName())[0];
endPoint = new IPEndPoint(HostIP, _Port);
UDPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UDPSocket.Bind(endPoint);

Unter Windows 7 wird aber dabei eine IPV6 Adresse zurückgegeben, mit welcher das Binden des UPD Socket nicht funktioniert.

Nachfolgend nun eine Methode die sowohl unter Windows XP (und den anderen älteren Betriebssystemen) als auch den aktuellen Betriebssystemen wie Windows 7 und W2K8 Server  funktioniert.

foreach (IPAddress address in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
{
    if (address.AddressFamily != AddressFamily.InterNetworkV6)
    {
        HostIP = address;
        break;
    }
}
endPoint = new IPEndPoint(HostIP, _Port);
UDPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UDPSocket.Bind(endPoint);
Code | C#
Monday, March 15, 2010 5:38:28 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, September 29, 2009

In einer Windows Anwendung wird in einer Form unter anderem ein (eigentlich sind es zwei, aber dazu später mehr) DateTimePicker verwendet um Termine einzugeben.

Da der DateTimePicker nicht gerade komfortabel ist um sowohl Datum als auch Uhrzeiten einzugeben, wird ein DateTimePicker in der Option DropDownCalender (das ist deaktivierte Eigenschaft ShowUpDown) eingesetzt um das Datum elegant aus dem DropDownCalender auszuwählen und ein zweites DateTimePicker Control mit der gesetzen Eigenschaft ShowUpDown und dem entsprechenden Custom Format HH:mm um nur die Uhrzeit mit den Pfeilen hoch und runter einstellen zu können.

image

Nun ist es aber so, dass man im DateTimePicker keinen Inkrement Wert eingeben kann, um den die Minuten erhöht bzw vermindert werden wenn man einmal auf den Pfeil hoch oder runter klickt. Somit wird jeweils um eine Minute hoch oder runter gezählt.

In meinem Fall nun wollte der Kunde aber das Termine nicht Minutengenau sondern immer auf 15 Minuten (Viertelstunde) Basis, also 00, 15, 30 und 45 erfasst werden können.

Da ich nicht gleich ein eigenen Control entwickeln wollte, habe ich einfach eine kleine Routine in den Change Event des DateTimePicker eingebaut.

Nachfolgend der Code Ich denke die Routine ist selbsterklärend

private void startzeitTimePicker_ValueChanged(object sender, EventArgs e)
{
    DateTimePicker dtp = (DateTimePicker)sender;
    // Wenn nicht Minute nicht 0,15,45 oder 60 dann müssen wir was tun
    if ((((dtp.Value.Minute != 0) && (dtp.Value.Minute != 15)) && (dtp.Value.Minute != 30)) &&
        (dtp.Value.Minute != 45))
    {
        // Auch noch einfach, nur 14 Minuten drauf und gut ist
        if ((dtp.Value.Minute == 1) || (dtp.Value.Minute == 16) || (dtp.Value.Minute == 31) || (dtp.Value.Minute == 46))
        {
            dtp.Value = dtp.Value.AddMinutes(14);
        }
        else
        {
            // Zeit wurde heruntergezählt.
            if ((dtp.Value.Minute == 14) || (dtp.Value.Minute == 29) || (dtp.Value.Minute == 44) || (dtp.Value.Minute == 59))
            {
                int x = 14;     // Deshalb auf jeden Fall mal 14 Minuten abziehen,
                if (dtp.Value.Minute == 59)  // und wenn die Minuten auf 59 stehen, dann muss noch eine Stunde (60 minuten) mehr abgezogen werden
                {
                    x += 60;
                }
                dtp.Value = dtp.Value.AddMinutes(-x);
            }
            else // Wert muss manuell eingegeben worden sein, dann runden wir auf die nächst höhere Viertelstunde
            {
                for (int i = 0; i < 15; i++)
                {
                    int x = dtp.Value.Minute + i;
                    if ((x == 15) || (x == 30) || (x == 45) || (x == 60))
                    {
                        dtp.Value = dtp.Value.AddMinutes(i);
                        break;
                    }
                }
            }
        }
    }
}

Hoffe das hilft dem einen oder anderen (Oder mir selbst beim nächsten mal wenn ich vor dem gleichen Problem stehen Wink)

Code | Tips und Tricks | C#
Tuesday, September 29, 2009 12:39:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, August 07, 2009

In einer Anwendung verwende ich eine Klasse um die Appointmens eines Kalenders abzubilden. Diese Klasse ist relativ Komplex und um diesen Beitrag nicht ebenfalls zu komplex werden zu lassen, verwende ich hier eine (sehr) abgespeckte Version dieser Klasse um das Thema Sortierung einer ArrayListe von Komplexen Objekten zu veranschaulichen.
Die Verwendung einer ArrayList war hier zwingend vorgeschrieben (typisierte Listen List<Type> kamen nicht in Frage)

Zuerst einmal die Aufgabenstellung:

In einer ArrayListe (nennen wir Sie AppointmentList) befinden sich Termine in Form von Objekten (nennen wir sie Appointment). Diese Objekte haben unter anderem eine Eigenschaft (Property) Startdatum (vom Type DateTime).

Da die Appointment in der AppointmentList unsortiert vorliegen und eine Sortierung (eigentlich zwei Sortierungen Auf und Absteigend) nach dem Startdatum des Termins benötigt wird, bestand die Aufgabe die AppointmentList zu sortieren.

Die ArrayLIst verfügt über eine Methode Sort. Da es sich bei den zu sortierenden Objekten aber um ein Komplexe Klasse handelt, muss man der Sort Methode einen Comparer an die Hand geben, damit die Methode Sort Ihre Aufgabe durchführen kann.

Hier nun die Umsetzung:

Zuerst einmal die (komplexe) Klasse Appointment (eine abgespeckte Variante)

public class Appointment
{

    public Appointment()
    {
        appointmentGUID = Guid.NewGuid();
    }


    private readonly Guid appointmentGUID = new Guid("00000000000000000000000000000000");

    public Guid AppointmentGUID
    {
        get { return appointmentGUID; }
    }

    private DateTime startDate;

    public DateTime StartDate
    {
        get { return startDate; }
        set
        {
            startDate = value;
            OnStartDateChanged();
        }
    }

    protected virtual void OnStartDateChanged()
    {
    }


    private DateTime endDate;

    public DateTime EndDate
    {
        get { return endDate; }
        set
        {
            endDate = value;
            OnEndDateChanged();
        }
    }

    protected virtual void OnEndDateChanged()
    {
    }



    private string title = "";

    [DefaultValue("")]
    public string Title
    {
        get { return title; }
        set
        {
            title = value;
            OnTitleChanged();
        }
    }

    protected virtual void OnTitleChanged()
    {
    }


    public override string ToString()
    {
        return Title;
    }

}

Der Comparer für diese Aufgabe sieht dann so aus (Methode zum Sortieren mit Implementierung der IComparer Schnittstelle:

public class AppointmentComparer : IComparer
{
    private bool descendSorting;
    public AppointmentComparer(bool descend)
    {
        descendSorting = descend;
    }

    int IComparer.Compare(object a, object b)
    {
        var b1 = (Appointment)a;
        var b2 = (Appointment)b;

        if (descendSorting)
        {
            return DateTime.Compare(b2.StartDate, b1.StartDate);
        }
        else
        {
            return DateTime.Compare(b1.StartDate, b2.StartDate);
        }
    }

}

Und verwenden kann man diesen Comparer wie folgt:

            al.Sort(new AppointmentComparer(false));
            al.Sort(new AppointmentComparer(true));

al wurde dabei wie folgt deklariert:

ArrayList al = new ArrayList();
Code | C#
Friday, August 07, 2009 1:14:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Monday, March 02, 2009

Auch wenn wir uns im Zeitalter von NET Framework 3.5 befinden ist dieser Beitrag in der Überschrift mit .NET 2.0 beschrieben, da sich in an dem Konzept der Anwendungseinstellungen seit .NET 2.0 keine Änderungen ergeben haben.

Mit dem Konzept der Anwendungseinstellungen wurde ein mehr oder weniger durchgängiges Konzept zur Speicherung und Verwendung von Anwendungs- und Benutzerspezifischen Daten eingeführt.

Bei der Einstellungen für eine Anwendung wird dabei zwischen zwei Bereichen (Benutzer / Anwendung) unterschieden.

Im Bereich Benutzer können die Einstellungen aus dem Programmcode sowohl gelesen als auch geschrieben werden.

Beispiel (Überprüfen ob eine Einstellung korrekt ist, wenn nicht dann aktualisieren und speichern):

// Lagereinheit Report
reportName = Settings.Default.Lagereinheit_ReportName;
if (!File.Exists(reportName))
{
    string tempName = File.GetFilenName(reportName);
    tempName = Application.StartupPath + "\\Reports\\" + tempName;
    if (File.Exists(tempName))
    {
        Settings.Default.Lagereinheit_ReportName = tempName;
        Settings.Default.Save();
    }
}

Im Bereich Anwendung können die Einstellungen aus dem Programmcode lediglich gelesen werden (Schreibgeschützt), der obige Programmcode würde also einen Fehler erzeugen, da die Anwendungseinstellungen Schreibgeschützt sind.

Was aber, wenn man eine Einstellung die als Anwendungseinstellung definiert ist, durch Programmcode ändern und in die Config Datei zurückschreiben muss.

Dann kann man dazu folgende statische Methode verwenden:

private static void setAppSetting(string SettingdName, string SettingValue)
{
    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.PreserveWhitespace = true;
    xmlDoc.Load(config.FilePath.Trim());
    XmlNode appSettingNode = xmlDoc.SelectSingleNode("configuration/applicationSettings");
    XmlNode settingNode = appSettingNode.SelectSingleNode(string.Format("//setting[@name='{0}']", SettingdName));
    XmlNode valueNode = settingNode.SelectSingleNode("value");
    valueNode.InnerText = SettingValue;
    xmlDoc.Save(config.FilePath.Trim());
}

Nachfolgend ein Beispiel wie man diese Methode im Programmcode einsetzt um eine “normerweise Schreibgeschütze” Einstellung zu ändern.

// auf normalem Weg lesend auf die Anwendungseinstellung zugreifen
if (Properties.Settings.Default.ApplicationVerladestelle == "DDC") 
{
	// Und hier mit Hilfe der setAppSetting Methode einen neuen Wert zuweisen und in die config Datei schreiben
    setAppSetting("ApplicationVerladestelle", "DCW");  
}

Settings.Default.Reload();  // Nicht vergessen, die aktuellen Werte noch mal zu laden
Code | Tips und Tricks
Monday, March 02, 2009 4:43:27 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [7]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, January 06, 2009

Hintergrund

In einer Windows Form Applikation wird in einer Form ein DataGridView verwendet das je nach Bedarf Schreibgeschützt (Alle Spalten) oder zur Eingabe von Daten (nicht Schreibgeschützt) verwendet werden soll. Soweit würde die Anforderung auch kein Problem darstellen, wenn - aber dazu lest einfach den Rest des Beitrags.

Nun ist es aber so, dass auch in der Variante indem das DataGridView als Eingabe (also nicht Schreibgeschützt) verwendet wird, die eine oder andere Spalte des DataGridView sehr wohl (zur Zeit der Entwicklung, also nicht zur Laufzeit) auf Schreibgeschützt gesetzt wurden.

Eigentlich sollte das ganze kein Problem darstellen, also "Einfach sein", wie es im Lied der FANTA4 beschrieben ist, aber wie geht es im Lied weiter; "is es aber nicht", und genau so ist es auch in dem hier beschriebenen Fall.

Das Problem liegt daran, dass durch das setzen der ReadOnly Eigenschaft des DataGridView auf True das DataGridView "vergisst" welche Spalten des DataGridView während der Entwicklungszeit auf ReadOnly gesetzt wurden.

Nachdem man während der Laufzeit die ReadOnly Eigenschaft des DataGridView einmal auf True und dann später wieder zurück auf False gesetzt hat, sind alle Spalten, auch diese die vorher ReadOnly waren plötzlich nicht mehr Schreibgeschützt.

Die Idee

Die Idee der nachfolgenden Lösung war schnell entstanden und wird im folgenden beschrieben.

Beim Start der Windows Form (am besten direkt im Konstruktor) muss man die Information der Schreibgeschützten Spalten sichern, und diese nachdem die ReadOnly Eigenschaft des DataGridView zurück auf False geändert wurde, einfach wieder auf die ursprünglichen Werte herstellen.

Die Lösung

Um die Information, welche Spalten beim Start der Windows Form Schreibgeschützt sind zu speichern, verwende ich ein typisiertes Array von int Werten um den Spalten Index der Schreibgeschützten Spalten zu sichern.

private List<int> saveReadOnlyColumn;

Die Logik zum Speichern der Informationen habe ich in eine eigene Methode (siehe nachfolgenden Code der Methode saveReadOnlyColumnInformation) ausgelagert, welche ich dann einfach am Ende des Konstruktor aufrufe.

private void saveReadOnlyColumnInformation()
{
    saveReadOnlyColumn = new List<int>();

    foreach (DataGridViewColumn o in dgVerladung.Columns)
    {
        if (o.ReadOnly)
        {
            saveReadOnlyColumn.Add(o.Index);
        }
    }
}

So nun haben wir die Informationen der Schreibgeschützten Spalten im typisierten Array für den späteren Gebrauch gespeichert.

Dann kümmern wir uns nun noch darum, diese gespeicherte Information immer dann wenn die ReadOnly Eigenschaft auf False gesetzt wurde, wieder auf die Startwerte zurücksetzen.

Hierzu können wir einfach den ReadOnlyChanged Event des DataGridView verwenden, welcher immer dann ausgelöst wird, wenn man im Code die ReadOnly Eigenschaft ändert.

Nachfolgend ist der Code dargestellt um die vorher gespeicherten Schreibgeschützten Spalten wieder herzustellen

private void dgVerladung_ReadOnlyChanged(object sender, EventArgs e)
{
    if (dgVerladung.ReadOnly == false)
    {
        foreach (int i in saveReadOnlyColumn)
        {
            dgVerladung.Columns[i].ReadOnly = true;
        }
    }
}

 

Der Vollständigkeit halber hier noch der Code des Konstruktor's (Hier erklärt die Zeile 4) dargestellt.

public formPlanungen()
{
    InitializeComponent();
    saveReadOnlyColumnInformation();
    Application.Idle += new EventHandler(Application_Idle);
}
Programmierung | Code | Tips und Tricks | C#
Tuesday, January 06, 2009 11:26:34 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, November 04, 2008

Problemstellung

Die Daten eines DataGridView sollen über die Zwischenablage in verschiedene andere Anwendungen (unter anderem auch in Excel) kopiert und eingefügt werden können.

Hierbei soll es wahlweise Möglich sein, beim kopieren in die Zwischenablage, die Spaltenköpfe des DataGridView mit in die Zwischenablage zu kopieren. Außerdem soll es neben der Tastenkombination Strg + C auch über Programmcode (Button und oder Contextmenü) möglich sein, die Daten in die Zwischenablage zu kopieren.

Umsetzung - Teil 1 Spaltenüberschriften einschließen

Ob die Spaltenköpfe beim kopieren der DataGridView Daten mit einbezogen werden kann über die Eigenschaft ClipboardCopyMode des DataGridView gesteuert werden.

Die Eigenschaft kann auf folgende Werte gesetzt werden:

image

Der Standardwert lautet EnableWithoutHeaderText (Kopieren der markierten Daten ohne Spaltenköpfe).

Um sicherzustellen, dass auch die Spaltenköpfe mit in die Zwischenablage kopiert werden, muss der Wert EnableAlwaysIncludeHeaderText gesetzt werden.

DataGridView1.ClipboardCopyMode = EnableAlwaysIncludeHeaderText ;

Umsetzung - Teil 2 Programmatisches kopieren der Zwischenablage

Um per Programmcode die Daten (mit oder ohne Spaltenköpfe) in die Zwischenablage zu kann der folgende Code verwendet werden:

Clipboard.SetDataObject(DataGridView1.GetClipboardContent(), true);
Programmierung | Code | C#
Tuesday, November 04, 2008 2:50:43 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, October 29, 2008

Die Anforderung:

In einem gebundenen DataGridView, soll eine Suchfunktion implementiert werden, die es ermöglicht, dass man je nach angewählter Spalte innerhalb der Spalte nach einem in ein Suchfeld einzugebenden Text gesucht werden kann. Allerdings soll nicht nur auf genaue Übereinstimmung, sondern auch nur auf Teil -Übereinstimmung der dem Suchbegriff entsprechende erste Eintrag gefunden werden.

Die Problematik:

Grundsätzlich wird für die Umsetzung der Anforderung von der BindingSource eine Methode Find zur Verfügung gestellt.

Beispiel:

bool found = false;

int i = customerBindingSource.Find(dgCustomer.SortedColumn.DataPropertyName, txtSearch.Text);
if (i > -1)
{
    customerBindingSource.Position = i;
}
else
{
}

Soweit funktioniert das Prima, wenn der Suchtext genau mit dem Inhalt der Zelle entspricht.

Was aber wenn zum Beispiel in einer Spalte die Werte für den Name der erste Eintrag der mir M beginnt gefunden werden soll?

Dann funktioniert die Find Methode nicht, und leider bietet weder die BindingSource noch das DataGridView hierzu eine entsprechende Möglichkeit dies einfach per Methodenaufruf zu realisieren.

Die Eine Lösung:

Schauen wir uns doch mal an, was wir mit dem oben noch leeren Else Zweig anfangen können.

Das wir über die BindingSource nicht weiter kommen haben wir schon festgestellt, also müssen wir uns selbst etwas basteln.

Beispiel:

string searchField = dgCustomer.SortedColumn == null ? 
"Hier einfach den DataPropertyName des gewünschten Standardsuchfeldes wenn keine Spalte markiert ist" : dgCustomer.SortedColumn.DataPropertyName;
string searchCellName = dgCustomer.SortedColumn == null ? 
"Hier einfach den Namen des gewünschten Standardsuchfeldes wenn keine Spalte markiert ist" : dgCustomer.SortedColumn.Name;
bool found = false;

int i = customerBindingSource.Find(searchField, txtSearch.Text);
if (i > -1)
{
	customerBindingSource.Position = i;
}
else            
{
	foreach (DataGridViewRow row in dgCustomer.Rows)
	{
		if (row.Cells[searchCellName].Value == null)
		{
			continue;
		}

		if (row.Cells[searchCellName].Value.ToString().ToLower().StartsWith(txtSearch.Text.ToLower()))
		{
			i = customerBindingSource.Find(searchField, row.Cells[searchCellName].Value.ToString());
			if (i > -1)
			{
				customerBindingSource.Position = i;
				found = true;
				break;
			}
		}
	}
	if (!found )
	{
		string msg = string.Format(CultureInfo.CurrentUICulture, "{0} {1} konnte nicht gefunden werden", searchField, txtSearch.Text);
		MessageBox.Show(msg);                                                
	}
}

Ich Denke der Code ist selbsterklärend und bedarf keiner weiteren Erklärung.

Wenn ich mich damit täuschen sollte, dann einfach per Kommentar die Fragen stellen, oder noch besser gleich die Antworten geben smile_regular.

Code | C#
Wednesday, October 29, 2008 9:19:30 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, April 08, 2008

Wer sich mit Drag und Drop innerhalb des DataGridView beschäftigt wird unter Umständen ermitteln wollen, ob die Maus auf einem Spalten oder Zeilenkopf gedrückt und festgehalten wurde. Zu diesem Zweck verwende ich die nachfolgende Methode "IsCellOrRowHeader".

Hier die C# Methode IsCellOrRowHeader:

private bool IsCellOrRowHeader(int x, int y)
{
    DataGridViewHitTestType dgt = dgTodo.HitTest(x, y).Type;
    return (dgt == DataGridViewHitTestType.Cell ||
                    dgt == DataGridViewHitTestType.RowHeader);
}

Ich glaube ich hatte die Methode als Grundgerüst mal in Internet gefunden, heute wo ich diesen Beitrag verfasse, habe ich die Suchmaschine angeworfen um einen Link auf den ursprünglichen Autor bzw, den Beitrag zu finden. Ich konnte aber die Seite nicht mehr finden, wenn also jemand dieses Beitrag liest und weiß wo der Ursprung dieser Methode herkommt, dann hinterlasst doch bitte einen Kommentar.

Eine VB Variante dieser Funktion habe ich gerade doch noch gefunden.

Hier der Link: IsCellOrRowHeader in VB

Programmierung | Code | C#
Tuesday, April 08, 2008 12:43:22 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, April 02, 2008

Erweiterungsmethoden sind statische Methoden die in statischen Klassen definiert werden und als ersten Parameter das Schlüsselwort this mit nachfolgendem Type der zu erweiternden Klasse an die Methode übergibt. Diese Erweiterungsmethoden werden dann als Instanz Methode (wie z.B. die ToString() Methode) des jeweiligen Objekts verwendet.

Vor einiger Zeit hatte ich einen Beitrag geschrieben der sich mit der C# Implementierung der unter VB verfügbaren Funktion isNumeric beschäftigte.

In diesem Beitrag hatte ich eine public static Methode in einer Helper Klasse geschrieben, ich dachte es wäre anschaulich wenn wir nun diese Implementierung als Erweiterungsmethode der String Klasse vornehmen.

Hier zuerst noch einmal die Klassische Implementierung vor C# 3.0

public static class MathHelper
{
    public static bool IsNumeric(object Expression)
    {
        bool isNum;
        double retNum;
        isNum = Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any,
                                System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
        return isNum;
    }
    
}

Diese konnte man wie folgt verwenden:

string o = "100";
if (MathHelper.IsNumeric(o))
    Console.WriteLine("Ja die Eingabe ist Numerisch");
else
    Console.WriteLine("Keine numerischen Eingabe");

So und nun zur Implementierung der isNumeric Funktionalität als Erweiterungsmethode der String Klasse:

Nun kann man mit dem C# 3.0 Feature der Erweiterungsmethoden (Extension Methods) diese aber auf viel elegantere weise lösen. Ich möchte dies hier an einem Beispiel der String Klasse demonstrieren. Wir erweitern also unsere String Klasse durch eine Erweiterungsmethode isNumeric.

Hierzu müssen wir zuerst eine Statische Klasse erstellen, in welcher wir dann die Erweiterungsmethode(n) deklarieren können.

public static class StringExtensions
{
    public static bool isNumeric(this string s)
    {
        double retNum;
        bool isNum = Double.TryParse(s, System.Globalization.NumberStyles.Any,
                                     System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
        return isNum;

    }
}

Verwendet wird das dann so:

string o = "100";
if (o.isNumeric())
    Console.WriteLine("Ja die Eingabe ist Numerisch");
else
    Console.WriteLine("Keine numerischen Eingabe");
Programmierung | Code | C#
Wednesday, April 02, 2008 11:01:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Thursday, February 14, 2008

Vor einiger Zeit hatte ich in meinem Beitrag: "enum Werte an ComboBox binden" beschrieben wie man die Werte von Aufzählungen an eine ComboBox binden kann.

Nun habe ich bereits mehrfach die Frage gestellt bekommen (zum letzten mal Gestern in einem Kommentar zu diesem Beitrag) wie man denn die Wert auch wieder auslesen kann.

Das geht zum Beispiel so:

private void cmbEnum_SelectedIndexChanged(object sender, EventArgs e)
{
    switch ((AppHeightDrawMode)cmbEnum.SelectedItem)
    {
        case AppHeightDrawMode.TrueHeightAll:
            break;
        case AppHeightDrawMode.FullHalfHourBlocksAll:
            break;
        case AppHeightDrawMode.EndHalfHourBlocksAll:
            break;
        case AppHeightDrawMode.FullHalfHourBlocksShort:
            break;
        case AppHeightDrawMode.EndHalfHourBlocksShort:
            break;
        default:
            break;
    }
}

 

Wobei der folgende Code das entscheidende ist:

(AppHeightDrawMode)cmbEnum.SelectedItem

Wir könnte damit auch so arbeiten:

AppHeightDrawMode myDrawMode = (AppHeightDrawMode)cmbEnum.SelectedItem;

Dabei steht dann in myDrawMode der Enum Wert der mit der ComboBox ausgewählt wurde.


Dieses Beispiel bezieht sich auf den Beitrag: enum Werte an ComboBox binden

Kurz und Bündig | Programmierung | Code | C#
Thursday, February 14, 2008 8:08:45 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, January 25, 2008

Der NET Framework stellt zur Kommunikation mit Windows Diensten die Komponente ServiceController aus dem Namespace System.ServiceProcess zur Verfügung.

Die Verwendung dieser Komponente ist relativ einfach (Siehe nachfolgendes Beispiel).

Hier ein einfaches Beispiel:

ServiceController myServiceController = new ServiceController("ServiceName");

if (myServiceController.Status == ServiceControllerStatus.Stopped )
{
    myServiceController.Start();
}

 

In diesem Beispiel wird für den Service "ServiceName" auf dem lokalen Rechner ein ServiceController erstellt, und anschließend wird geprüft ob der Service gestoppt ist und wenn, dann wird er gestartet.

Aber was ist wenn der Service "SeviceName" gar nicht auf dem lokalen Rechner installiert ist.

Leider besitzt die Komponente ServiceController keine Eigenschaft oder Methode mit welcher man einfach prüfen kann ob der Service auf dem Computer installiert ist.
Es kommt also zu folgender Fehlermeldung Laufzeitfehler:

image

Natürlich kann man mit einem Try Catch Block den Fehler abfangen, aber es geht auch anders, ich vermeide lieber einen vorhersehbaren Fehler als dann in einer Exception darauf zu reagieren.

Zur Demonstration wie man das anders regeln kann, habe ich eine kleine Beispielklasse Namens ServiceControllerHelper geschrieben die eine statische Methode getServiceControllerForService enthält. Dieser Methode übergibt man einfach den Names des Service und erhält, wenn es den Service gibt, ein ServiceController Objekt zurück andernfalls ein null.

Hier nun die Klasse ServiceControllerHelper:

using System;
using System.ServiceProcess;

namespace ServiceControlSample
{
    public static class ServiceControllerHelper
    {
        public static ServiceController getServiceControllerForService(string shortName)
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (ServiceController service in services)
            {
                if (service.ServiceName == shortName)
                {
                    return service;
                }
            }
            return null;
        }

    }
}

 

Und so kann man diese Klasse einsetzen:

ServiceController myServiceController;

 

myServiceController = ServiceControllerHelper.getServiceControllerForService("ServiceName");

 

if (myServiceController != null)
{
    if (myServiceController.Status == ServiceControllerStatus.Stopped )
    {
        myServiceController.Start();
    }
}

 

Dieser Beitrag soll lediglich als Einstig in dieses Thema Dienen und keine vollständige Implementierung einer ServiceControllerHelper Klasse darstellen.

Code | Tips und Tricks | C#
Friday, January 25, 2008 12:54:49 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, January 11, 2008

Manchmal ist es notwendig dass man die verschiedenen Werte einer Aufzählung zu einem eindeutigen Wert kombinieren kann.

Ein Beispiel dafür sind die Zugriffsrechte auf ein Objekt, sei es eine Datei im Dateisystem oder seien es Daten in einer Datenbank.

Nehmen wir an wir müssen zwischen den folgenden Rechten unterscheiden können:

  • Lesen
  • Schreiben
  • Löschen

Nun können wir entweder verschiedene Eigenschaften wie:

  • HasReadRights
  • HasWriteRights
  • HasDeleteRights

verwenden um jeweils das Lese, Schreib oder Löschrecht für ein Objekt zu hinterlegen, oder eben wir verwenden dazu eine Aufzählung.

public enum ObjectRights
{

Read = 0x01,
Write = 0x02,
Delete = 0x04

}

Wenn wir nun ein Objekt zur Speicherung einer solchen Aufzählung definieren können wir darin bereits die kombinierten Werte ablegen, allerdings werden die Werte dann als Integer Ergebnis der Bitweisen Oder Operation abgelegt.

Beispiel:

ObjectRights Rechte = ObjectRights.Read | ObjectRights.Delete;

Ergibt zum Beispiel in der Ausgabe mit:

System.Diagnostics.Debug.WriteLine(Rechte);

folgendes:

5

Das ist das Resultat der Bitweisen Oder Operation 0x01 | 0x04

Um nun aber anstelle der Integer Werte, die Aufzählungstypen als Bitfelder zu interpretieren müssen wir der Aufzählung ein zusätzliches Attribut [Flags] mitgeben. diese geschieht wie nachfolgend abgebildet:

[Flags]
public enum ObjectRights
{

Read = 0x01,
Write = 0x02,
Delete = 0x04

}

Wenn wir nun die Werte mit dem Bitweise Oder Operator kombinieren werden die Werte wie Bitfelder behandelt.

ObjectRights Rechte = ObjectRights.Read | ObjectRights.Write | ObjectRights.Delete

Die Ausgabe von Rechte mit System.Diagnostics.Debug.WriteLine(Rechte);

ergibt nun:

Read, Delete

Um abzufragen ob ein bestimmtes Recht gesetzt ist, können wir den Bitweise Und Operator verwenden:

if ((Rechte & ObjectRights.Read) == ObjectRights.Read)
{
    System.Diagnostics.Debug.WriteLine("Lesen erlaubt");
}

 

if ((Rechte & ObjectRights.Write) == ObjectRights.Write )
{
    System.Diagnostics.Debug.WriteLine("Schreiben erlaubt");
}

 

if ((Rechte & ObjectRights.Delete) == ObjectRights.Delete)
{
    System.Diagnostics.Debug.WriteLine("Löschen erlaubt");
} Kurz und Bündig | Code | C#

Friday, January 11, 2008 7:54:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, January 09, 2008

Vorab möchte ich festhalten, dass ich in diesem Beitrag lediglich die Information darüber geben möchte wie man unter C# das äquivalent zur Finalize Methode in VB implementiert. Dies soll keine Diskussion über die Verwendung von Garbage Collection oder von Managed und Unmanaged Code werden.

Eventuell werde ich dazu mal in einem separaten Beitrag meinen Senf dazu abgeben, nun aber zum eigentlichen Thema dieses Beitrags:

Die Finalize Methode die es unter VB gibt ist unter C# der Destruktor.

Um einen Destruktor für eine Klasse unter C# zu implementieren muss man eine Methode mit der Tilde und dem Klassennamen erstellen.

Also zu Beispiel muss der Destruktor für eine Klasse MyClass wie folgt deklariert werden:

~MyClass()
{

//Hier alles rein was im Destruktor aufgerufen werden muss um alle Ressourcen des Objektes freizugeben
// Eigentlich sollte man aber wenn man einen Destruktor deklariert mindestens die IDisposable Schnittstelle
// in seiner Klasse implementiert haben und dann auch die Dispose Methode im Destruktor aufrufen, siehe hier
Dispose(false);

}

Code | C# | VB
Wednesday, January 09, 2008 8:52:37 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, January 08, 2008

Kurze GUID Beschreibung.

GU steht für Global Unique

ID steht für identifier

Zusammen = Global unique identifier = Globaler eindeutiger Bezeichner

Eine Guid ist ein 128 Bit integer Wert der dazu verwendet werden kann einem Objekt einen eindeutigen Bezeichner hinzuzufügen.

Die am häufigsten verwendete Darstellung einer Guide erfolgt jedoch nicht in dezimaler sondern in hexadezimaler Darstellung.

Wobei zu Darstellung fünf Gruppen verwendet werden.

Erste Gruppe 8 Stellen, dann 3 Gruppen mit je 4 Stellen und eine fünfte Gruppe mit 12 stellen.

Beispiel GUID Standarddarstellung:

{f563e21d-dbc3-4b6e-a59e-0eb4d898c299}

Um nun einen solche GUID in C# zu erzeugen genügt folgender Code:

private Guid myGuid = Guid.NewGuid();

Kurz und Bündig | Code | C#
Tuesday, January 08, 2008 8:02:24 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Monday, January 07, 2008

Nachdem ich immer wieder mal gefragt werde wie man auf einfache weise enum Werte an Controls binden kann, hier unter dem Motto kurz und bündig ein Beispiel in C#.

Um die Werte eines Aufzählung's Typs (enum) an eine ComboBox (oder auch andere Controls die eine DataSource Eigenschaft zur Verfügung stellen) zu binden genügt nachfolgender Code:

Hier ein Beispiel mit eigenem enum (funktioniert natürlich auch mit System Typen)

public enum AppHeightDrawMode
{
    TrueHeightAll = 0,
    FullHalfHourBlocksAll = 1,
    EndHalfHourBlocksAll = 2,
    FullHalfHourBlocksShort = 3,
    EndHalfHourBlocksShort = 4,
}

comboBox1.DataSource = Enum.GetValues(typeof(AppHeightDrawMode));

Das Resultat sieht dann so aus:

 image

Kurz und Bündig | Code | C#
Monday, January 07, 2008 4:16:27 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [8]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, October 05, 2007

Immer wieder taucht die Frage auf, wie man auf einfache Art und Weise eine Datensicherung einer SQL Datenbank anlegen kann.

Auch wenn Heute viele gar nicht mehr genau wissen wozu man die Eingabeaufforderung, Batch Dateien und Kommandozeilen (das sind Programme die keine GUI haben) Programme verwendet ist die Zeit dieser Tools noch lange nicht zu Ende, wie auch dieser Beitrag wieder einmal beweist.

Und eines dieser Kommandozeilen Programme, das osql tool des SQL Server, ist auch die Basis dieses Artikel.

Das osql tool des Microsoft SQL Server (sowohl im SQL Server 2000, der MSDE und auch in allen SQL 2005 Versionen enthalten) bietet die Möglichkeit Transact SQL Befehle (T-SQL) direkt von der Kommandozeile auszuführen.

Nutzen wir doch diese Möglichkeit und erstellen wir uns eine Batch Datei (Datei die auf Kommandozeilen Ebene ausgeführt werden kann), mit der wir eine Datenbank eines SQL Server's sichern können.

Ich Denke nicht dass man jede Zeile der Batch Datei erklären muss, deshalb hier nun den Inhalt der Batch Datei:

@ECHO OFF
rem Für die Verwendung mit SQL Server 2000 oder der MSDE in der nachfolgenden Zeile  das rem am Anfang entfernen
rem set SQL_UTIL_HOME="%ProgramFiles%\Microsoft SQL Server\80\Tools\Binn\osql"
rem Für die Verwendung mit SQL Server 2005 oder SQL Server 2005 Express in der nachfolgenden Zeile  das rem am Anfang entfernen
set SQL_UTIL_HOME="%ProgramFiles%\Microsoft SQL Server\90\Tools\Binn\osql"
rem Tragen Sie in der nachfolgenden Zeile den Namen des SQL Server ein z.B. (localhost)
set SQL_SERVERNAME=HP-DN01\SQL2005
rem Tragen Sie in der nachfolgenden Zeile den Namen der zu sichernden Datenbank ein
set SQL_DBNAME=FASC
rem Tragen sie den Namen inkl. Pfad der Backup Datei ein
set SQL_BACKUP_FILE='C:\temp\fasc.bak'
@ECHO ON
%SQL_UTIL_HOME% -E -S%SQL_SERVERNAME% -n -Q "BACKUP DATABASE %SQL_DBNAME% TO DISK = %SQL_BACKUP_FILE% WITH INIT"

Hier kann man die Datei herunterladen Backup.Bat.

Einfach herunterladen, das ZIP File entpacken und dann die Backu.BAT Datei öffnen und die darin gesetzten Environment Variablen auf die eigenen Bedürfnisse anpassen.

 

Code | Tips und Tricks | Tools
Friday, October 05, 2007 10:40:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Thursday, October 04, 2007

Im Zusammenhang mit einem DotNetNuke Update (Version 3.1.1 --> Version 4.5.3) welches ich für einen Kunden durchführe ist folgendes Problem aufgetaucht:

In der DotNetNuke Installation 3.1.1 war unter anderem das FAQ Module von SpohnSoftware in der Version 1.06.00 eingesetzt.

Während des Update des DotNetNuke Portals auf die Version 4.5.3 traten auch keine merklichen Probleme mit diesem Modul auf. Selbst bei den ersten Tests (es handelt sich um ein umfangreiches Portal) wurden zuerst noch keine Probleme festgestellt. Dann aber stellte man fest, dass beim Versuch durch anklicken der Frage die Antwort zu öffnen nur eine Meldung "Fehler auf dieser Seite" vom Browser ausgegeben wurde, aber der Antwort nicht angezeigt wurde.

Nach einer kurzen Recherche im Internet war klar, es gibt eine neue Version (mittlerweile die Version 03.00.00) die auch laut Angaben des Herstellers für DotNetNuke 4.X funktioniert.

Also neue Version des Moduls gekauft (wie sich kurz drauf herausstellen sollte, Gott Sei Dank gleich die Source Version) und auf einem Test-Portal installiert.

  • Frage und Antwort eingegeben
  • Seite aufgerufen
  • Auf die Frage geklickt um die Antwort anzuzeigen

Und der Browser zeigt in der Statuszeile an: Fehler auf dieser Seite

Wie bereits erwähnt, ich hatte die Source Version gekauft. Also das Modul in einem Entwicklungsportal installiert und die Source in das Projekt integriert.

Fehlersuche......!

Nach einigen Minuten war klar, das Problem liegt daran dass beim Aufruf von Java Script Funktionen kein gültiges Objekt der Seite an diese als Parameter übergeben wurden, aber warum.

Aber auch diese Frage war nach kurzer Zeit geklärt:

SpohnSoftware hat in seinem Modul eine Funktion GetTableName die dazu verwendet wird den durch das APS.NET Framework generierten Namen für das Control zu ermitteln. Die Funktion sieht so aus:

        Public Function GetTableName() As String
            Try
                Return Replace(UniqueID & "_tblQA", ":", "_")

            Catch ex As Exception
                ProcessModuleLoadException(Me, ex)
            End Try
        End Function

Wenn wir uns nun den Replace anschauen sehen wir auch sehr schnell das eigentliche Problem:

Die UniqueID enthält den eindeutigen Namen, welcher vom NET Framework erzeugt wurde. Das NET Framework 2.0 verwendet hierbei zur Trennung zwischen den einzelnen Namen das $ Zeichen und nicht das : Zeichen.

Das kann nicht gehen und ich frage mich wie das Modul jemals funktioniert haben soll.

Hier nun die Funktion wie sie richtig ist und auch funktioniert:

        Public Function GetTableName() As String
            Try
                Return Replace(UniqueID & "_tblQA", "$", "_")

            Catch ex As Exception
                ProcessModuleLoadException(Me, ex)
            End Try
        End Function

Ich habe hierzu auch sehr intensiv im Internet recherchiert, konnte aber keine Erklärung finden, warum das jemals so funktioniert haben soll.

Mal sehen, eventuell gibt es ja jemand der meinen Artikel liest und mir darauf eine Antwort geben kann.

DotNetNuke | Module | Programmierung | Code
Thursday, October 04, 2007 8:12:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, August 15, 2007

Jetzt reicht es und ich mache mir selbst ein Geschenk indem ich nun endlich dieses Problem einmal in einem Blog Eintrag festhalte.

Hintergrund:

Immer wieder stehe ich vor der Aufgabe das ich von irgendwoher Daten aus einer Datei verarbeiten (meistens Importfunktionen) muss, die unter anderem auch Datums und oder Zeitwerte enthalten.

Die Werte werden in den verschiedensten Formaten übergeben, eine der beliebtesten Formate ist es aber dass beideInformationen (Datum und Uhrzeit) in zwei verschiedenen Felder übergeben werden. Dabei wird häufig (jedenfalls ist das bei mir so) das nachfolgende Format für die Speicherung der Werte verwendet:

Datum als String z.B. : 20070815 also im Format yyyyMMdd

Uhrzeit als String z.B. : 120310 also im Forma HHmmss

Nun besteht die Aufgabe darin diese Daten zu lesen und dann in ein DateTime Objekt zu konvertieren.

Lösung:

Nachfolgend nun die von mir favorisierte und schon dutzende male verwendet Lösung:

// Source ist in C#

 string dateStr = s[2]; // Hier steht einfach ein Datumswert wie 20070815 drin
 string timeStr = s[3]; // Hier steht eine Uhrzeit wie 120310 drin 
 string dateTimeStr = dateStr + " " + timeStr; //Da steht nun  20070815 120310 also Datum mit Uhrzeit drin
 string dateTimeStrFormat = "yyyyMMdd HHmmss"; // Genau hier das ist das Format

 // Und hier wird nun der zusammen gebastelte Datum  / Uhrzeit String in ein DateTime Objekt konvertiert
 objInfo.TransDate = DateTime.ParseExact(dateTimeStr, dateTimeStrFormat, DateTimeFormatInfo.InvariantInfo);

So und nun hoffe ich das ich beim nächsten mal nicht wieder nach diesem Stückchen Quellcode suche wenn ich mal wieder vor der Aufgabe stehe, und eventuell stolpert ja auch der eine oder andere über diese Information wenn er / sie mal so etwas machen möchte.

Programmierung | Code | Tips und Tricks | C#
Wednesday, August 15, 2007 10:16:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Monday, July 30, 2007

Ich weiß nicht wie oft ich schon da stand, und mir mal wieder die Frage gestellt habe, wie unter c# das äquivalent für die in vb verfügbare Funktion isnumeric lautet.

Und immer wieder benötige ich einiges an Zeit um wieder mal herauszufinden dass es kein direktes äquivalent gibt, aber es gibt halt doch eine ganz einfache Lösung.

Man implementiert sich eine solche Funktion mal schnell selbst. Es gibt dazu eine ganze Reihe von ansätzen, so nach dem Motto; viele Wege führen nach Rom.

Ich möchte nun hier meinen persönlichen Favorit dokumentieren, so dass ich Ihn nicht wieder vergesse, ganz nach dem Motto, was du mal geschrieben hast, vergisst du nicht mehr so schnell.

Und hier der Ersatz für die aus vb bekannte isnumeric Funktion:

  1. public static bool IsNumeric(object Expression)   
  2. {   
  3.     bool isNum;   
  4.     double retNum;   
  5.     isNum = Double.TryParse(Convert.ToString(Expression),       System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);   
  6.     return isNum;   
  7. }  
Programmierung | Code | C#
Monday, July 30, 2007 10:12:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, May 09, 2007

Wenn Sie die URL zu Ihrer Webseite ändern müssen, sollten Sie bereits vorher die richtigen Maßnahmen ergreifen, dass ein Internet Surfer der auf diese Seite zugreifen möchte nicht den häßlichen Fehler 404 (Datei nicht gefunden) angezeigt bekommt.

Eine durchaus übliche Lösung hierfür ist es ein meta refresh hierfür zu verwenden.

Auf der URL eines Seite anzulegen welche als einzigen Inhalt den nachfolgenden meta refresh enthält.

meta http-equiv="refresh" content="0; URL=http://www.Domain.de/" />

Der oben dargestellte meta refresh leitet ohne Zeitverzögerung den Internet Surfer auf die im Parameter URL stehende neue Webseite um.

 

So weit so Gut, aber !!

Es gibt 3 Gründe warum man dies nicht machen sollte:
  1. Sie werden diese Umleitung ewig bestehen lassen müssen, da der Internet Surfer nie wirklich etwas von Ihrer neuen Internetseite erfährt.
  2. Suchmaschinen bewerten solche Umleitungen häufig als SPAM und streichen wenn Sie Pech haben, all Ihre Seiten aus Ihrer Datenbank.
  3. Das Thema Ranking spielt hier eine Rolle. Ich Denke jeder kennt das PageRank von Google. Also nehmen wir einmal an Sie hatten auf der alten URL einen PR von 5, im besten Fall akzeptiert die Suchmaschine Ihre Umleitung und behält Ihren Eintrag in Ihrer Datenbank. Das Ranking der Seite liegt aber weiterhin auf der alten URL und wird nicht zu einem eventuelle Ranking der neuen Seite hinzugezogen.

Was geschieht bei einem Redirect egal ob über meta-equiv oder über Source Code "Context.Response.Redirect".

Die Seite wird umgeleitet und im Response Header wird ein Status Code 302 zurückgeben.

Dieser Status kommt sagt aus das die URL gefunden wurde. Gefunden bedeutet aber, Sie musste gesucht werden, nicht Gut !!

Wenn ein URL Zugriff einwandfrei verläuft dann sollte ein Status Code 200 zurückgegeben werden.

So jetzt haben wir was von Status 200 und 302 gehört, aber wie können wir es erreichen dass wir durch unseren Redirect die Suchmaschinen nicht böße machen und dass die neue URL als Quelle der Information im Internet bekannt wird.

 

Die Lösung heißt: Permanente Weiterleitung.

Eine Permanente Weiterleitung ist im ersten Moment auch nur ein Redirect, aber der zurückgegeben Status Code ist 301 (URL wurde verschoben). Diese Information nutzen die meisten Suchmaschinen um Ihre Einträge auf die neue URL in Ihren Datenbanken zu aktualisieren. Das hat den Vorteil. dass nach einige Zeit die Informationen über die neue URL direkt in den Suchmaschinen zur Verfügung stehen, und ganz wichtig, das auf der alten liegende PageRank wird auf die neue URL übernommen.

 

Wie kann ich jetzt eine Permanente Umleitung erstellen:

Mit einem meta-equiv leider nicht (nicht in ASP.NET)

Aber für was haben wir denn ein intelligentes Framework auf dem unser Web läuft.

Zu diesem Zweck erstellen wir einfach eine ASPX Seite die dem alten URL Namen entspricht.

 

In diese ASPX Datei schreiben wir folgenden Inline Code:

<%@ Page Language="vb" AutoEventWireup="false"%> 
<SCRIPT runat="server"> 
Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
Context.Response.Status = "301 Moved Permanently" 
Context.Response.AddHeader("Location", "<http://www.schelian.de/Default.aspx/tabid/189>") 
End Sub 
</SCRIPT>

Wenn Sie nun die Datei auf dem Server gespeichert haben wird eine permanente Suchmaschinenfreundliche Umleitung vorgenommen.

 

Hier ein Beispiel http://www.schelian.de/MindManager.aspx

 

Dieser Link wird auf den URL http://www.schelian.de/default.aspx/tabid/155  umgeleitet.

Und nun viel Spaß beim suchmaschinenfreundlichen Umleiten von Seiten!

ASP.NET | Code | VB
Wednesday, May 09, 2007 9:19:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]  
Autor: Hans-Peter Schelian  |  Trackback
Copyright © 2010 Hans-Peter Schelian - Schelian IT Beratung. All rights reserved.