Dokumentation der Dotnetnuke Datenbank (ERD) der Version 4.4.0

Wer schon immer mal eine Datenbankmodell-Digramm der DNN-Datenbank haben wollte, kann diese nun einfach downloaden. Die Datenbankstruktur der DNN-Version 4.4.0 wurde dabei dokumentiert. Es stehen drei verschiednen Formate zur Verfügung: PDF VISO HTML Windows-Hilfe Hier gib es den Download des ERD Modells

Performanceoptimierung von DotNetNuke / DNN

Das DotNetNuke mittlerweile einen sehr großen und brauchbaren Funktionsumfang hat muss an dieser Stelle nicht weiter erwähnt werden. Bei der Implementierung alle dieser Features stand aber leider der Punkt Geschwindigkeit (Performance) nie im Mittelpunkt. Das soll nun endlich mit der kommenden Version 4.4.0 verändert werden! Durch folgende Maßnahmen soll die Geschwindigkeit verbessert werden: (1) Code Refactoring (2) Optimierung und verbesserte Einsatz des Caching (3) Assembly Management (4) Database (5) Compression (6) Page State Wer genauer wissen möchte was sich hinter den einzelnen Punkten versteckt kann das im Blogeintrag von Charles Nurse hier nachlesen. Die Ergebnisse der ersten Tests kann man hier nachlesen! Auf die Version 4.4.0 dürfen wir also alle sehr gespannt sein :)

Microsofts Ajax (Atlas) steht als RC zum Download bereit

Auch wenn ich bis jetzt das Thema Ajax hier wohl mehr stiefmütterlich behandelt habe, habe ich dieses immer im Fokus. Das von Microsoft entwickelte Ajax-Framework steht nun als RC zur Verfügung und kann hier runtergeladen weden. Jetzt kann man also über einen ernsthaften Einsatz nachdenken und ich werde das Thema nun endlich angehen.

DotNetNuke und entfernen von Profilproperties

Für einen Bekannten habe ich eine DotNetNukeinstallation (4.3.6) aufgesetzt und ihn ein wenig damit spielen lassen. Dabei hat er sich auch ein wenig mit den Profileigenschaften eines Users beschäftigt und diese Modifiziert. Das finde ich doch schon sehr gut und hätte ich mir eigentlich von Anfang an gewünscht .. Da sein Portal lediglich den deutschsprachigen Raum anspricht hat er einfach die Eigenschaft TimeZone gelöscht. Leider findet das DotNetNuke gar nicht witzig und normale Anwender konnten sich ab diesem Zeitpunkt nicht mehr anmelden. Einige Komponenten benötigen diese Profileigenschaft und es kracht ganz schön böse, falls diese nicht im Profil enthalten ist. Also: Vorsicht beim Löschen von Profileigenschaften - lieber ausblenden:)

DotNetNuke 3.3.6 / 4.3.6 steht zum Download bereit

Seit gestern gibt es die aktuelle Version von DotNetNuke auf der offiziellen Downloadseite zur Verfügung. Neben einigen Fehlern, Sicherheitslücken und Peformanceoptimierung wurde auch mal die Datensyncronisation verbessert. Genaue Informationen gibt es wie immer hier. Die Deutsche Übersetzung findet man bei http://www.deutschnetnuke.de/

MenuPilot: Open source context menu ASP.NET

Ein sehr schönes Context-Menü für ASP.net 2.0 habe ich soeben hier entdeckt. Dabei wird die Smart-Tag-Technologie (bekannt z.B. aus dem VS.NET 2005) verwendet. Ebenso gibt es unter http://www.daypilot.org/ einen Klasse ASP.NET Kalender im Look & Feel von Outlook 2003  .. 

SqlException: Konflikt der Sortierung fur die equal to-Operation

"Konflikt der Sortierung für die equal to-Operation kann nicht aufgeloest werden." Was will der von mir???? ;-) Nach dem Umzug einer DotNetNuke - Site auf eine anderen Server bekam ich plötzlich im Log Viewer die Fehlermedlung DotNetNuke.Services.Exceptions.ModuleLoadException: Konflikt der Sortierung für die equal to-Operation kann nicht aufgelöst werden. ---> System.Data.SqlClient.SqlException: Konflikt der Sortierung für die equal to-Operation kann nicht aufgelöst werden. at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) at Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteReader(SqlConnection connection, SqlTransaction transaction, CommandType commandType, String commandText, SqlParameter[] commandParameters, SqlConnectionOwnership connectionOwnership) at Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteReader(String connectionString, CommandType commandType, String commandText, SqlParameter[] commandParameters) at Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteReader(String connectionString, String spName, Object[] parameterValues) at DotNetNuke.Services.Log.EventLog.DBLoggingProvider.Data.SqlDataProvider.GetLog(Int32 PageSize, Int32 PageIndex) at DotNetNuke.Services.Log.EventLog.DBLoggingProvider.DBLoggingProvider.GetLog(Int32 PageSize, Int32 PageIndex, Int32& TotalRecords) at DotNetNuke.Services.Log.EventLog.LogController.GetLog(Int32 PageSize, Int32 PageIndex, Int32& TotalRecords) at DotNetNuke.Modules.Admin.Log.LogViewer.BindData() at DotNetNuke.Modules.Admin.Log.LogViewer.Page_Load(Object sender, EventArgs e) --- Ende der internen Ausnahmestapelüberwachung --- Nach ein wenig Forschung war die Lösung schnell gefunden. Die SP muss ein wenig verändert werden, damit der Fehler nicht mehr auftritt. Die Stored Procedure "GetEventLog" muss von     CREATE TABLE #PageIndex     (        IndexID        int IDENTITY (1, 1) NOT NULL,        LogGUID    varchar(36)     ) auf    CREATE TABLE #PageIndex     (        IndexID        int IDENTITY (1, 1) NOT NULL,        LogGUID    varchar(36) COLLATE database_default     ) geändert werden. Dann ist wieder alles im Lot!

Ein CSS Menu fuer DotNetNuke 3.x / ASP.NET

Ich möchte jetzt hier gar keine Diskussion lostretten die über das Solpart-Menu herzieht. Fakt ist auf jeden Fall: Das Anpassen des Menü via CSS kann einem wirklich graue Haare bereiten Die Größe des Menü (bezogen auf die HTML Datei) ist sehr groß Die Suchmaschinenfreundlichkeit ist fast nicht gegeben Aus diesen Gründen habe ich ein kleines niedliches CSS-Menu gebaut das mit HTML Aufzählungen, CSS und wirklichen Links (!) arbeitet. Es ist noch kein perfektes Menu aber für meine derzeitigen Einsatzbereich wirklich ausreichend. Ein paar Erweiterungen und Optimierungen müssen da in Zukunft noch implementiert werden. Aber wie bei jedem Projekt gibt es auch hier mal eine Version 1.0. Da ich sehr gerne und eigentlich fast alle DotNetNuke Module in C# entwickel ist auch dieses Modul ist c# geschrieben. Die Einbindung in ein Skin ist relativ simple! Einfach folgendes in das Skin aufnehmen: <%@ Register TagPrefix="gwc" Namespace="GaliNeo.Modules.Framework" Assembly="GaliNeoMenu" %> und dann an der Stelle wo das Menü erscheinen soll: <gwc:GaliNeoMenu runat="server" id="TestMenu"></gwc:GaliNeoMenu> Natürlich läst sich damit so ziemlich jede Menü darstellen das sich mit den HTML Tags UL und CSS formatieren läßt. Hier ist es zunächst ein klassisches Drop-Down Menü....Hier der Download des Source-Codes:GaliNeo.DotNetNukeMenu (1.0.0.0).zip (7,96 KB)

Ein DotNetNuke Skin ohne Table-Tags rein auf DIV/CSS basierend

Ja ja ... i know. Wochenlang habe ich mein Blog vernachläßigt und jetzt jagt ein Beitrag den anderen ;-) Aber irgendwie habe ich mir heute ein wenig Zeit genommen um durch das www zu surfen. Hier ist noch eine Seite, die man keinen DNN Skin Designe vorenthalten sollte: http://www.xhtmlskins.com/ Auf dieser Seite geht es um die Erstellung von DotNetNuke Skins ohne Tabellen. Total sexy :)

Generierung von Barcode on the fly

Hier ein paar Blogbeträge zum Thema Barcodes und wie man diese unter DotNet erzeugen kann ohne 3rd-party Komponenten:Code 39 barcodes in C#ISBN to EAN-13 (C#)An ASP.NET .ashx HTTP handler for Code 39 barcode generation

Posting Form Data with c#

Letztes Jahr habe ich folgenden Blog-Eintrag verfasst. Darum ging es, wie man ein HTML-Form innerhalb von .NET simulieren kann. Jetzt ist mir gerade aufgefallen, dass der Sourcecode der ausführenden Klasse dafür fehlt. Natürlich ist das der spannende und entscheidene Part für das Post der HTML-Form. Das möchte ich natürlich nicht so stehen lassen und hier kommt der fehlende Part! using System;using System.Net;using System.Web;using System.IO;using System.Text ;namespace GaliNeo.Framework{    public class RemotePost    {        #region Private Members        private System.Collections.Specialized.NameValueCollection Inputs = null ;        private string _sUrl = "" ;        #endregion                public RemotePost()        {            //            // TODO: Fügen Sie hier die Konstruktorlogik hinzu            //            Inputs = new System.Collections.Specialized.NameValueCollection() ;        }        #region Public Methods        public void Add(string sName, double dValue)        {            this.Add(sName, dValue.ToString()) ;        }        public void Add(string sName,int iValue)        {            this.Add(sName, iValue.ToString() ) ;        }                public void Add(string sName,string sValue)        {            Inputs.Add(sName,sValue) ;        }        public string Url        {            get { return _sUrl ; }            set { _sUrl = value ; }        }                public string Send()        {            string sPostData = "" ;            Uri sUri = new Uri(this.Url) ;                    //Wird für evtl. SSL - Verbindungen benötigt            System.Net.ServicePointManager.CertificatePolicy = new trustedCertificatePolicy();            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(sUri);            //User-Agent            request.UserAgent = "GaliNeo OnlineStore" ;            request.Method = "POST";            request.ContentType = "application/x-www-form-urlencoded";                        //Zusammensetzen der Daten für die Übermittlung            sPostData = GetContentToPost() ;                        request.ContentLength = sPostData.Length ;                        Stream writeStream = request.GetRequestStream();                        //Encoding im UTF-8 Format um kompatible zu sein            //UTF8Encoding encoding = new UTF8Encoding(); //UFT-8 funktioniert unter ASP.NET nicht :(            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding() ;                        byte[] bytes = encoding.GetBytes(sPostData);            writeStream.Write(bytes, 0, bytes.Length);            writeStream.Close();            HttpWebResponse response = (HttpWebResponse) request.GetResponse();                        //Überprüft den HTTP-Statuscode            if (response.StatusCode != HttpStatusCode.OK)            {                return "N,-1, HTTPStatuscode:" +response.StatusCode.ToString() ;            }            Stream responseStream = response.GetResponseStream();            StreamReader readStream = new StreamReader (responseStream, Encoding.UTF8);            return readStream.ReadToEnd();                 }        public string GetContentToPost()        {            string sReturn = "" ;            for(int i=0; i< Inputs.Keys.Count;i++)            {                if (sReturn.Length == 0)                {                    sReturn = Inputs.Keys[i] + "=" + Inputs[Inputs.Keys[i]] ;                }                else                {                    sReturn += "&" + Inputs.Keys[i] + "=" + Inputs[Inputs.Keys[i]] ;                }//    if (sPostData.Length == 0)            }//for(int i=0; i< Inputs.Keys.Count;i++)            return sReturn ;        }        #endregion    }}

Bitte warten Sie in ASP.NET oder eine BusyBoxDotNet

Soeben habe ich eine sehr coole Komponente entdeckt, die es einem relativ einfach ermöglicht bei einer ASP.NET WebForm einen "Bitte warte Sie"-Dialog / BusyBox einzubelnden. Dieses ASP.NET Komponenten ist sehr anpassbar und scheint auf dem ersten Blick sogar schon in der Version 0.2.1 sehr brauchen zu sein. Das Opensource Projekt heißt "BusyBoxDotNet" und ist hier zu finden. Mal schauen wie sich die Komponente unter DotNetNuke verhält und ob man diese für eine Modulentwicklung einsetzen kann. Die Komponente ist nur für ASP.NET 2.0 verfügbar ...

DotNetNuke 3.3.3 Final Release

Die letzten Monate war es um DotNetNuke ja doch recht ruhig geworden. Mittlerweile kommt aber wieder Leben in den Releasezyklus :) Vor wenigen Tagen wurde die Version 3.3.3 veröffentlich, die als Final Release bezeichnet wird. Hier ist ein Auszug aus den Änderungen (die Orginalfassung findet man unter dotnenuke.com): Membership ManagementCAPTCHA - eine bekannte Technologie, die mehr Sicherheit bei der Anmeldung verspricht. In einem Bild werden Zahlen und oder Buchstaben angezeigt, die der Benutzer bei der Anmeldung eingegben muss. Durch die Darstellung als Bild es es dann nicht mehr so ohne weiteres möglich eine brute force Attacke durchzuführen.Login Redirect - Nach der Anmeldung kann man die User zu einer definierten Seite weiterleitenPassword Generation - Als Administrator kann man nun automatisier ein Passwort für einen Anwender verwegeben.Public Registration - Beim diesem Anmeldetyp wird nun auch eine E-Mail an den Benutzer geschickt - damit kann man den Mißbrauch von Daten vorbeugen.Profile Change Notification - Anwender werde über Änderungen in Ihrem Profil per E-Mail informiert.User Account Creation Notification - Wenn ein Administrator ein Benutzerkonto anlegt, dann können nun die Daten an den entsprechenden Benutzer verschickt werden.Force Profile Update - Der Benutzer kann dazu "gezwungen" werden, nach einem Login sein Profil u verändern.Force Password Change - Bietet die Möglichkeit das der Anwender sein Passwort erneuern muss.Password Complexity - Der Aufbau und die Komplexität der Passwörter lassen sich definieren.Preserve Login Parameters - Wenn ein Benutzer zur Anmeldung geleitet wird, dann wird nun die Herkunftsurl ausgelesen und gespeichert, damit anschließend dahin zurück geleitet werden kann.Automated Verified Registration URL - Der Benutzer bekommt per E-Mail eine URL und sobald er diese aufruft wird das Konto freigeschaltet.User Lockout Notification - Wen ein Benutzerkonto gesperrt wird (durch die falsche Eingabe vom Passwort), bekommt der Administrator darüber eine E-Mail. Role ManagementEffective Date - Ab wann soll eine Rolle gültig sein.Role Groups - Rollen können nun zu Gruppen zusammengefasst werden.UsabilityRich Text Editor - Nun können Verlinkungen zu Seiten im Poral direkt angelegt werden.Newsletter - Die Abenderadresse kann definiert werden. FrameworkAccessDeniedURL - Hierfür kan nu eine Seite definiert werden.PerformanceModule Settings - Seiten und Moduleinstellungen werden nun gecached :). Module Definitions/InstallerModule Definitions - Die Moduledefinition kann nun direkt durch eine *.dnn Datei angelegt werden, ohne eine Zip-Datei hochzuladen.OtherSMTP Settings - Die Portnumber kann angepasst werdenNew Modules - Store, Forums, Blogs, Gallery sind nun Bestandteil der aktuellen Version.

Es ist so weit DNN 3.3.0 steht zum Download bereit

In der Mittagspause noch mit einem Bekannte über DNN diskutiert und das es in der letzten Zeit doch recht still geworden ist .... musste ich gerade feststellen das das Core-Team von DotNetNuke heute das neue Release 3.3.0 zum Download frei gegeben hat. Leider komme ich in den nächsten nicht dazu diese Version zu testen aber in den Foren gibt es dazu bestimmt jede Menge zu lesen - oder auch nicht, wenn alles ohne Probleme verläuft.Es bleibt aber dabei: Zuerst die Installationsanweisung von DotNetNuke lesen und auf jeden Fall eine komplette Datensicherung von Datenbank und Dateisystem durchführen. Die deutsche Übersetzung gibt es wie immer unter Sebastian Leupold.

Parameter aus einem Querystring entfernen.

Gerade habe ich einen interessanten Artikel gefunden der zeigt, wie man einen Parameter aus der Querystringauflistung entfernen kann. Public Sub RemoveQueryString(ByVal Req As HttpRequest, ByVal strKeyToDel As String, ByVal http_Context As HttpContext)Dim nvc As System.Collections.Specialized.NameValueCollection = New System.Collections.Specialized.NameValueCollection(Req.QueryString)Dim sPage As String = Req.ServerVariables("SERVER_NAME") & Req.ServerVariables("SCRIPT_NAME")nvc.Remove(strKeyToDel)Dim strNewURL As String = Req.PathDim sSeparator As String = "?"Dim sKey As StringFor Each sKey In nvcIf sKey <> Nothing ThenDim sValues As String() = nvc.GetValues(sKey)Dim sValue As StringFor Each sValue In sValuesIf sValue <> Nothing ThenstrNewURL &= sSeparatorstrNewURL &= sKey & "=" & sValuesSeparator = "&"End IfNextEnd IfNextIf nvc.Keys.Count < 1 ThenstrNewURL &= "?"End Ifhttp_Context.Current.RewritePath(strNewURL)End Sub Gefunden habe ich den Code unter http://www.codeproject.com

DNN (DotNetNuke) und Transaktionen

Eines meiner größten Probleme - oder sagen wir lieber Sorgen - war bisher, dass DNN keine Transaktionen unterstützt. Es gibt doch immer wieder mal Business-Cases wo man transaktionsicher Daten verarbeiten möchte. Ein typischens Beispiel wäre z.B. eine Online-Shop, wenn es um die Bestellung und gleichzeitige Zahlungsabwicklung geht. Da DotNetNuke in vermutlich in vielen Fällen auf einem Windows 2003 Server betrieben wird, ist die komplette Umgebung schon vorhanden um die Abläufe transaktionssicher zu gestalten. Das Stichwort ist hier "Services without Components". Der Begriff "Services without Components" steht für die Nutzung von COM+-Dienste in .NET-Anwendung ohne Registrierung als Serviced Component (COM+-Anwendung).Klassen: .ServiceConfig and System.EnterpriseServices.ServiceDomain Das folgende Beispiel zeigt eine ganz einfache Implementierung innerhalb einer Methode:                  //Hier wird mit einem Transaktionskontext gearbeitet,                //damit das Handling einfacher wird                ServiceConfig sc = new ServiceConfig();                sc.Transaction = TransactionOption.RequiresNew ;                ServiceDomain.Enter ( sc ) ;                try                {                    //mach was ....                    ContextUtil.SetComplete() ;                }                catch (Exception exc)                 {                    ContextUtil.SetAbort() ;                    throw exc ;                }                finally                {                    ServiceDomain.Leave();                }  

Architects Connection

Seit einigen Tagen existiert ein eigenes Informations-Portal für IT-Architekten (www.architectsconnection.de). Dort stehen sehr viele  architekturrelevanten Ressourcen – Fachartikel, Kommentare, Web- und PodCasts, Vorträge, Event-Termine u.v.m  zur Verfügung und soll bei den täglichen Aufgaben helfen und unterstützen. Der Gedanke des Portals ist "Service von Architekten für Architekten". Schauen wir mal wie sich dieses Microsoft Portal entwickelt. 

Exportieren / Umwandeln von DataTable in CSV

Bevor ich aber mit .NET 2.0 so richtig loslege hier noch ein kleiner Codebeitrag. Man hat ja immer wieder die Anforderung Daten in CSV zu exportieren (im Zeitalter von XML für mich unverständlich aber gut ;-) ). Dafür veröffentliche ich jetzt das fünftausenste Code-Beispiel. Zunächst habe ich eine allgemeine Basisklasse geschrieben, die auch für weiter Exportformate genutzt werden kann: using System;using System.Data;using System.Web;using System.Text;using System.IO;namespace GaliNeo.Framework{    /// <summary>    /// Zusammenfassung für BaseConverter.    /// </summary>    public abstract class BaseConverter    {        public BaseConverter()        {        }        /// <summary>        /// Export DataTable to http stream        /// </summary>        /// <param name="oDataTable"></param>        /// <param name="response"></param>        /// <param name="sFileName"></param>        public void ExportToResponseStream(DataTable oDataTable, System.Web.HttpResponse response, string sFileName)        {            response.Clear() ;            response.ClearHeaders();            response.ClearContent();            response.Buffer = true;                        //Very importent because "ü", "ä", usw....            response.ContentEncoding = System.Text.Encoding.Default ;                        response.ContentType = GetHTTPContentType() ;            response.AppendHeader("content-disposition", "attachment; filename=" + HttpUtility.UrlEncode(sFileName, System.Text.Encoding.UTF8)) ;            response.Write( ConvertDataTable(oDataTable).ToString() ) ;                        //close http response            response.End();        }        /// <summary>        /// Export datatable to file        /// </summary>        /// <param name="oDataTable"></param>        /// <param name="sFileName"></param>        /// <returns></returns>        public bool ExportToFile(DataTable oDataTable, string sFileName )         {            try            {                string fullpath = System.IO.Path.GetFullPath( sFileName ) ;                if (System.IO.Directory.Exists ( fullpath ))                {                    System.IO.Directory.CreateDirectory( fullpath ) ;                }                StreamWriter SW;                            SW=File.CreateText(sFileName);                SW.WriteLine(ConvertDataTable(oDataTable).ToString());                            SW.Close();                return true ;            }            catch            {                return false ;            }        }        protected abstract StringBuilder ConvertDataTable(DataTable oDataTable) ;        protected abstract string GetHTTPContentType() ;    }}   Die Klasse ermöglicht es eine Stream entweder auf Festplatte zu schreiben oder aber in den HTTP Responsestream. Die passende CSV-Klasse ist relativ simple und kein wirkliches Geheimnis: using System;using System.Data;using System.IO;using System.Text;namespace GaliNeo.Framework{    /// <summary>    /// Summary description for CSVConvertor.    /// </summary>    public class CSVConverter : BaseConverter    {                protected override string GetHTTPContentType()         {            return "text/csv";        }        /// <summary>        /// To generate CSV file.        /// </summary>        /// <param name="oDataTable"></param>        /// <param name="directoryPath"></param>        /// <param name="fileName"></param>        /// <returns></returns>        protected override StringBuilder ConvertDataTable(DataTable oDataTable)         {                        StringBuilder oStringBuilder = new StringBuilder();                                     // Start, Creating column header            foreach(DataColumn oDataColumn in oDataTable.Columns)                {                oStringBuilder.Append(oDataColumn.ColumnName + ",");                oStringBuilder.Append( System.Environment.NewLine ) ;            }             //End, Creating column header             //Start, Creating rows            foreach(DataRow oDataRow in oDataTable.Rows)                {                                                foreach(DataColumn oDataColumn in oDataTable.Columns)                    {                    oStringBuilder.Append(oDataRow[oDataColumn.ColumnName] + ",");                }                oStringBuilder.Append( System.Environment.NewLine ) ;            }                         //End, Creating rows            return oStringBuilder;        }    }}   Fertig!  

Loesung: Suchen in der ASPNET_PROFILE Table / DotNetNuke Profil

So, nach ein wenig google etwas Arbeit habe ich jetzt ein Lösung gefunden, die sogar recht performant aussieht. Zunächst noch ein paar Basics: Die Tabelle ASPNET_PROFILE beinhaltet folgende Felder: UserId PropertyNames PropertyValuesString PropertyValuesBinary LastUpdatedDate Das Feld PropertyNames beinhaltet eine mit ":" separierte Zeichenfolge, die definiert welche Benutzereigenschaften / -properties gespeichert werden. Zusätzlich wird die Position dort angegeben. Ein Beispiel: FirstName:S:39:7 Dieser (Teil-)Eintrage besagt das die Property den Namen "FirstName" hat, vom Typ String "S" ist, an der Postion 39 anfängt und 7 Zeichen lang ist. Um nun einzelene Daten zur extrahieren, habe ich mir eine die Funktionalität der UDF (User Defined Functions) vom Microsoft SQL Server bzw. der MSDE zu nutze gemacht. Diese Funktionen können direkt aus SQL-Statements aufgerufen werden. CREATE FUNCTION dbo.GaliNeo_UDF_GetElement(@ord AS INT,@strToParse AS VARCHAR(8000),@seperator AS VARCHAR(1) )RETURNS INTASBEGIN   -- Wenn die Eingabeparatemer null sind, wird auch null zurück gegeben  IF  @strToParse IS NULL      OR LEN(@strToParse) = 0      OR @ord IS NULL      OR @ord < 1       OR @ord > LEN(@strToParse) - LEN(REPLACE(@strToParse, @seperator, '')) + 1    RETURN NULL   DECLARE @ipos AS INT, @curord AS INT   SELECT @ipos = 1, @curord = 1   -- nächsts Element suchen  WHILE @curord < @ord    SELECT      @ipos    = CHARINDEX(@seperator, @strToParse, @ipos) + 1,      @curord = @curord + 1  RETURN    CAST(SUBSTRING(@strToParse, @ipos, CHARINDEX(@seperator, @strToParse + @seperator, @ipos) - @ipos) AS INT)END Die GaliNeo_UDF_GetElement ist eine sehr allgemein Funktion um mit separierte Strings in SQL-Queries zu arbeiten. Sehr hilfreich war dabei ein Artikel auf der Seite WindowsItPro. Diese Funktion können wir nun in der eigentlichen UDF "GaliNeo_UDF_GetProfileElement" nutzen: CREATE FUNCTION dbo.GaliNeo_UDF_GetProfileElement(@fieldName AS NVARCHAR(100),@fields AS NVARCHAR(4000),@values AS NVARCHAR(4000))RETURNS NVARCHAR(4000)ASBEGIN   IF  @fieldName IS NULL      OR LEN(@fieldName) = 0      OR @fields IS NULL      OR LEN(@fields) = 0      OR @values IS NULL      OR LEN(@values) = 0    RETURN NULL DECLARE @fieldNameToken AS NVARCHAR(20)DECLARE @fieldNameStart AS INTEGER, @valueStart AS INTEGER, @valueLength AS INTEGER SET @fieldNameStart = CHARINDEX(@fieldName + ':S',@Fields,0) IF @fieldNameStart = 0 RETURN NULLSET @fieldNameStart = @fieldNameStart + LEN(@fieldName) + 3 SET @fieldNameToken = SUBSTRING(@Fields,@fieldNameStart,LEN(@Fields)-@fieldNameStart) SET @valueStart = dbo.GaliNeo_UDF_GetElement(1,@fieldNameToken,':')SET @valueLength = dbo.GaliNeo_UDF_GetElement(2,@fieldNameToken,':') IF @valueLength = 0 RETURN '' RETURN SUBSTRING(@values, @valueStart+1, @valueLength)END Aus einer SQL Query kann jetzt diese Funktion wie folgt genutzt werden:SELECT dbo.GaliNeo_UDF_GetProfileElement('PostalCode',PropertyNames,PropertyValuesString) FROM aspnet_Profile So, das tat doch mal wieder fast nicht weh und bei 10.000 Profilen ist es von der Performance noch in Ordnung. Mal schauen wie es sich verhält, wenn man etwas mehr Daten in er DB hat.