Bei der Umstellung eines ASP.NET Projektes auf das Framework 4.0 wurde bei bestimmten Eingabedaten immer der Fehler geworfen: System.Web. HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (_dataTextBox="...bitkarte (<print template="pay..."). at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) at System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) at System.Web.HttpRequest.get_Form() Dieses konnte man unter ASP.NET 2.0 durch ein @pagedirektive unterdrücken bzw. die Filterung ausschalten. Bei ASP.NET 4.0 ist dieses per @pagedirektive aber nicht mehr per Default möglich, es gibt aber die Möglichkeit die RequestValidierung per Eintrag in die web.config wieder in den Modus "ASP.NET 2.0" zu versetzen, damit das Verhalten gleich bleibt. Dafür ergänzt man die web.config wie folgt: <httpRuntime requestValidationMode="2.0" /> Weiter Informationen gibt es in der MSDN.
Bei der Weiterentwicklung eines recht alten Portals stand ich nun vor der Aufgabe eine aktuelle Entwicklungsumgebung aufzusetzen. Die bisherige Umgebung war DNN 3.2.2 und nun wurde das Portal auf die aktuelle Version von DNN (4.x) aktualisiert. Da ich auch nicht mehr mit Visual Studio 2003 entwickeln wollte, habe ich den SourceCode das Modul mit dem Conversion Wizard auf die aktuelle VSS Version 2008 konvertiert. Das Projekt vom Type ClassLibrary konnte aber nicht vernüftigt debugged werden, daher habe ich beschlossen das Projekt als WAP (Web Application Project) weiterzuentwickeln. Dafür muss man (nach erfolgreichem Durchlaufen des Conversion Wizard von VS2008) die Projektdatei mit einem Editor öffnen und anschließend die Zeile <ProjectType>Local</ProjectType> gegen <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> tauschen. Nach dem erneuten Öffnen der Projektmappe / des Projektes im Visual Studio wird diese nun als WAP angezeigt. Nun muss man nur noch die einzlnen ASCX / ASPX in eine Web-Anwendung konvertieren. Das ist auch sehr einfach zu erledigen: Die gewünschten Dateien Auswählen und im Kontextmenü den Punkt "In Webanwendung konvertieren" wählen. Nun werden im Hintergrund die *.designer.cs Dateien angelegt und gleichzeitig die Codebehind-Klassen als "partial" gekennzeichnet. Schon ist das Update von einer Class Library in ein Web Application Project fertig! Achso: Bitte die Konfiguration überprüfen und evtl. Anpassen...
Bei der Entwicklung von DotNetNuke-Modulen (bzw. auch bei "normalen" ASP.NET Anwendungen) verwende ich recht häufig die Möglichkeit, Usercontrols (ascx) dynmaisch zur Laufzeit anzuzeigen / nachzu laden. Der entsprechende Quellcode dafür ist nicht wirklich neu und sieht so aus: PortalModuleBase objToLoad = this.LoadControl(_ControlToLoad) as PortalModuleBase;
objToLoad.ID = System.IO.Path.GetFileName(_ControlToLoad);
objToLoad.ModuleConfiguration = this.ModuleConfiguration;
this.Controls.Add(objOrderCtrl);
Wichtig dabei ist die Zeile, wo die ID des Controls gesetzt wird, damit die Resourcendateien durch DotNetNuke (durch die Property LocalResourceFile) angesprochen werden können. Bei der Verwendung einer Templateengine für ein Modul und der gleichzeitigen Verwendung von Standard ASP.NET 2.0 Validatoren, bekam ich im Browser immer die Javascript-Fehlermeldung "missing ; before statement". Nach kurzer Recherche habe ich die Ursache gefunden: In den ID's von den Controls wurde ein Punkt verwendet und damit kommt JavaScript bzw. der JavaScript-Code der ASP.NET Validatoren nicht zurecht. Nach Abänderung der ID Zuweisung auf folgende Zeile: objToLoad.ID = System.IO.Path.GetFileNameWithoutExtensi(_ControlToLoad);
funktionieren sowohl die Resourcendateien als auch die Validatoren wieder ohne Probleme.
In unserem DotNetNuke Shop Modul wird im Administationsbereich einiges mit ASP.NET AJAX durchgeführt. Bisher verlief die Installation der Entwicklungsumgebung auch immer ohne Probleme. Bei einem Kollegen, kam es aber zu einer echt blöden Fehlermeldung:
DotNetNuke.Services.Exceptions.ModuleLoadException: The base class includes the field 'pnlExtPrice', but its type (System.Web.UI.UpdatePanel) is not compatible with the type of control (System.Web.UI.UpdatePanel). ---> System.Web.HttpParseException: The base class includes the field 'pnlExtPrice', but its type (System.Web.UI.UpdatePanel) is not compatible with the type of control (System.Web.UI.UpdatePanel). ---> System.Web.HttpParseException: The base class includes the field 'pnlExtPrice', but its type (System.Web.UI.UpdatePanel) is not compatible with the type of control (System.Web.UI.UpdatePanel). at System.Web.Compilation.BaseTemplateCodeDomTreeGenerator. BuildFieldDeclaration(ControlBuilder builder) at System.Web.Compilation.BaseTemplateCodeDomTreeGenerator. BuildSourceDataTreeFromBuilder(ControlBuilder builder, Boolean fInTemplate, Boolean topLevelControlInTemplate, PropertyEntry pse) at System.Web.Compilation.BaseTemplateCodeDomTreeGenerator. BuildSourceDataTreeFromBuilder(ControlBuilder builder, Boolean fInTemplate, Boolean topLevelControlInTemplate, PropertyEntry pse) at System.Web.Compilation.TemplateControlCodeDomTreeGenerator.
BuildMiscClassMembers() at System.Web.Compilation.BaseCodeDomTreeGenerator.BuildSourceDataTree() at System.Web.Compilation.BaseTemplateBuildProvider. GenerateCode(AssemblyBuilder assemblyBuilder) at System.Web.Compilation.AssemblyBuilder.AddBuildProvider(BuildProvider buildProvider) --- End of inner exception stack trace --- at System.Web.Compilation.AssemblyBuilder.AddBuildProvider(BuildProvider buildProvider) at System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.UI.TemplateControl.LoadControl(VirtualPath virtualPath) at System.Web.UI.TemplateControl.LoadControl(String virtualPath) at DotNetNuke.UI.Skins.Skin.InjectModule(Control objPane, ModuleInfo objModule, PortalSettings PortalSettings) --- End of inner exception stack trace ---
Eigentlich war alles so weit auch richtig installiert und in einer anderen DNN Installation lief AJAX ohne größere Probleme. Auf dem Rechner war neben ASP.NET 2.0 auch bereits .NET 3.5 installiert und ich dachte mir schon, das es irgendein Konflikt mit den Versionen sein muss. Eine Recherche im Web hat mich dann auf folgendes Ergebnis gebraucht:
In der web.config muss der Bereich "runtime" wie folgt angepasst werden: <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="bin;bin\HttpModules;bin\Providers;bin\Modules;bin\Support;" /> <dependentAssembly> <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" /> <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" /> </ependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35" /> <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" /> </dependentAssembly>
</assemblyBinding> <runtime>
Danach läuft das Modul und die AJAX Funktionen - hier im speziellen das UpdatePanel - wieder ohne Probleme.
Das ich im letzten Jahr eine Videoportal Software auf Basis von DotNetNuke mit WCF Services im Backend entwickelt habe, ist hier ja schon ein paar mal erwähnt wurden. Die bis jetzt aufgesetzten Videoportale können natürlich auch die hochgeladenen Videos in Flash konvertieren (sorry Silverlight ). Aktuell wird dafür das Tool FFMpeg genutzt, dass auch einen guten Dienst leistet und recht flexibel ist. Durch die asyncrone Entkopplung der einzelnen WCF Services ist auch so ein Command-Line Tool im Hintergrund kein wirkliches timing Problem.
Heute habe ich per Zufall aber gesehen, dass es nun .NET Lib für die Konvertierung gibt - getestet habe ich diese noch nicht - könnte aber evtl. eine denkbare Alternative sein.
Laut Website auch für den Einsatz in webbasierter Software gut geeignet. Die Lib ist kostenlos, wer den SourceCode haben möchte, muss dafür ein paar Dollar hinlegen.
Mehr Infos gibt es hier: http://www.intuitive.sk/fflib/
Wer sich wundert das die Funktion "Anmeldedaten merken" im IE nicht funktioniert und sich ebenfalls darüber ärgert, für den habe ich nun eine Lösung (vielmehr habe ich im Web eine gefunden). Im Blog auf www.dotnetnuke.com habe ich einen Beitrag gefunden der erklärt, wieso, weshalb, warum und was man dagegen tun kann. Hier ist der Beitrag...Prinzipell müssen zwei Einträge in der web.config angepasst werden, damit die Funktion das macht, was sie soll: <forms name=".DOTNETNUKE" protection="All" timeout="120" cookieless="UseCookies" />
<add key="PersistentCookieTimeout" value="20160" />
Der "Fehler" liegt auch weniger an DNN sonder viel mehr an der Behandlung von Cookies unter ASP.NET 2.0.
Heute habe ich versucht, den FCKEditor innerhalb eines ASP.NET Ajax Updatepanel dazu zu bewegen mir auch den eingegebenen Text auszuhändigen. Normalerweise ist ja die Einbindung und Nutzung vom FCKEditor innerhalb von DotNetNuke denkbar einfach. Also wie gewohnt die Arbeitsschritte ausgeführt und mal mutig F5 gedrückt. Leider mit dem Resultat, dass die Eigenschaft Text vom FCKEditor nach einem partial PostBack immer leer war und der Text zunächst mysteriös verschwand. Die Suchmaschine meines Vertrauen hat mir auch prompt ein paar Hinweise zu dem Thema ausgespuckt - gut, ich war wohl nicht alleine auf dieser Welt.
Auf der Seite http://jlcoady.net/archive/2007/03/30/fckeditor-work-inside-updatepanel wurde ein Lösungsansatz vorgestellt, der aber leider so nicht ganz funktioniert - zumindest im meinem Fall nicht.
private void Page_Load(object sender, EventArgs args) { Page.ClientScript.RegisterOnSubmitStatement( editor.GetType(), "editor", "FCKeditorAPI.GetInstance('" + editor.ClientID + "').UpdateLinkedField();"); }
Dieser Code-Snippet bracht mich nicht weiter, denn der Text wurde immer noch nicht zurück geliefert, nach einem Postback innerhalb vom UpdatePanel.
Auch der folgende Code sollte angeblich funktionieren, konnte aber meine FCKEditor auch nicht wirklich übereden, mal endlich seine Arbeit aufzunehmen.
this.Page.ClientScript.RegisterOnSubmitStatement( this.GetType(), "AjaxHack", "for ( var i = 0; i < parent.frames.length; ++i ) if ( parent.frames[i].FCK ) parent.frames[i].FCK.UpdateLinkedField();" );
Wie sich nun herausstellt, sind die Scripte vollkommen in Ordnung und funktionieren auch. Nur ist es empfehlenswert die Methode "RegisterOnSubmitStatement" nicht als Methode der Page aufzurufen sondern als Methode vom ScriptManager. Das sieht dann so aus:
ScriptManager sm = ScriptManager.GetCurrent(Page); if (sm != null) { ScriptManager.RegisterOnSubmitStatement(this.Page, this.GetType(), "FCKAjaxHack", "for ( var i = 0; i < parent.frames.length; ++i ) if ( parent.frames[i].FCK ) parent.frames[i].FCK.UpdateLinkedField();"); }
Oh Wunder, jetzt funktioniert auch der FCKEditor in der Zusammenstellung von DotNetNuke, ASP.Net Ajax und dem Updatepanel!
Bei der Neuinstallation eines Windows 2008 Server mit ASP.NET 2.0 und AJAX bekam ich beim Abruf von Resourcen über WebResource.axd und ScriptResource.axd jeweils den Fehler:
Specified argument was out of the range of valid values. Parameter name: utcDate
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: utcDate
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. |
Lösung:
Das liegt an der Systemzeit vom Windows Server. Zunächst sollte diese Zeit überprüft werden und falls nötig auf das aktuell Datum / Uhrzeit gesetzt werden.
Sollte dadurch der Fehler nicht behoben werden, dann einfach unter Software die Installation von AJAX mit der Option "Reparieren" durchführen. Es scheint hier wohl eine Fehler zu geben und ASP.NET AJAX kommt dann mit dem Datum nicht zurecht. Nach der "erneuten" Installation funktioniert dann alles wie gewollt!
Wer sich mit tabellenlosen Designs beschäftigt - und sind wir mal ehrlich, ergibt es anders einen Sinn - der wird sich auch immer wieder mal mit dem DOCTYPE rumschlagen müssen. Zum Glück haben die Entwickler von DotNetNuke da auch mitgedacht und den DOCTYPE pro DNN-Portal, sogar pro DNN Skin konfigurierbar gestaltet.
Dafür muss lediglich eine XML-Datei angelegt werden, die den Namen des Skins trägt und dann die Endung ".doctype.xml" hat also von Aufbau her so aussieht [SKINNAME].doctype.xml.
Die XML Datei hat folgenden Aufbau:
<SkinDocType> <![CDATA[<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">]]> </SkinDocType>
Fertig ist der angepasste DOCTYPE für ein DotNetNuke-Skin.
Das war doch mal wieder einfach :)
Auch während Weihnachten war das DNN-Core-Team wohl nicht ganz untätig und hat am 27.12.2007 den Download der DotNetNuke Version 4.8.0 frei gegeben. Es wurden viele Fehler korrigiert und neu ist der Support von DNN für den IIS (Internet-Information-Server) 7.0. Wer sich einen genauen Überblick von den Änderungen der aktuellen DNN Version machen möchte - Bitteschön, wie immer geht das im Bugtracking System support.DotNetNuke.com
Also zunächst mal: Ich lebe noch Auch wenn mein Blog in den letzten Wochen eigentlich etwas anderes vermuten läßt. In den letzten Woche stecke ich in einem größeren Projekt wo ich DotNetNuke und die WCF (Windows Communication Foundation) mit einander kombiniert habe, um ein Videoportal (so in Richtung youtube, myvideo, etc.) zu entwicken. Doch dazu später hoffentlich mehr....
Seit heut steht DotNetNuke 4.7.0 zur Verfügung und wurde für die Öffentlichkeit als Download bereit gestellt. Dieses wurde pünktlich zur US-Konferenz OpenForce'07 bekannt gegeben. Dabei finde die neuen benutzerfreundlichen URLs sehr spannend. Leider komme ich im Augenblick noch nicht dazu, diese zu testen. :(
Immer wieder kommt die Situation das man im Laufe eines .NET Programmes überprüfen muss ob eine Objekt wirklich existiert oder aber ob in der Variablen der Wert NULL enthalten ist. Vielfach möchte man auch einfach für den NULL Fall einen Defaultwert setzen. Mit dem ?? Operator ist das in .NET C# sehr elegant und einfach zu realisieren.
Hier ein ganz einfaches Beispiel:
string resultmessage = param ?? "Keine Nachricht da ";
In der MSDN findet man dazu auch nähere Informationen (hier )
Hier eine Liste der wichtigsten (zumindest für mich) Escape-Sequencen:
-
\t Tab (Unicode 0x0009).
-
\r Carriage return (0x000d).
-
\n Newline (line feed) (0x000a).
-
\v Vertical tab (0x000b).
-
\a Alert (0x0007).
-
\b Backspace (0x0008).
- \0 Null (0x0000).
-
\\ Backslash (0x005c).
-
\' Single quote (0x0027).
-
\" Double quote (0x0022).
In der kommenden Version von DotNetNuke (DNN 4.6.0) ist ein sehr interessantes Feature die Möglichkeit der Implementierung von neuen Authentifizierungssystemen jenseits von DNN. Nun ist es nicht nur mehr möglich sich gegen DotNetNuke oder einer ADS (Active Directory Service) zu authentifizieren, sondern eine Anmeldung kann nun durch:
Dafür wurde ein "neues" Providermodell für die Authentifizierung implementiert. In den letzten Tagen habe ich für einen Kunden bereits einen eigenen Provider für eine Anmeldung bei der zentralen Golf-Online-Seite erstellt und erste positive Erfahrungen damit gesammelt. Dafür muss man lediglich drei UI-Komponenten entwickeln: Login, Settings and LogOff – jeweils von Basisklassen abgeleitet (AuthenticationLoginBase, AuthenticationSettingsBase and AuthenticationLogOffBase). Die Konfiguration der einzelnen verfügbaren Provider wird über die Tabelle Authentication vorgenommen. Dort wird ganz einfach ein Prefix und die drei UI-Komponenten angegeben.
Es ist auch möglich dem Benutzer die Auswahl selber zu überlassen, mit welchem Dienst er sich Authentifizieren möchte – das find ich insgesamt schon ziemlich sexy.
Wenn sich der Benutzer über z.B. LiveID angemeldet hat, dann wird nach erfolgreicher Authentifizierung ein Benutzerkonto angelegt oder aber man kann diesen Login mit einem existierenden DNN-Benutzerkonto verknüpfen. In der Datenbank gibt es dafür die Tabelle: UserAuthentication
Bei der Suche nach Performancemessungen für ein .NET Projekt, habe ich ich folgende interessante(s) Seite / Projekt gefunden:
ProfileSharp
Bis jetzt nur kurz getestet, scheint es aber ein gute Lösung zu sein um:
- Eine Speicheranalyse durchzuführen (z.B. Memoryleaks)
- Wo welche Rechenleistung benötigt wird
Besonders interessant ist, dass der Profiler keinerlei Veränderungen am SourceCode benötigt - Bestandteile des Profilers müssen also nicht in das Projekt / Assembly k(c)ompiliert werden. Er läßt sich einfach von außen anfügen
Das Produkt ist OpenSource und steht damit jedem zur Verfügung. Ob bei dem Funktionsumfang / Leistung mit kommerzielle Produkten aufnehmen kann werd ich sehen.
Wenn man eine Anwendung nur einmal durch den Anwender starten lassen möchte, dann ist das mit der Hilfe von einem erzeugten Mutex sehr einfach zu realisieren.
Nur ein paar Zeilen Quellcode sind dafür in der Main() Methode notwendig. Wie immer ist der Beispiel-Code in .NET C#.
bool createdNew; ///Einen neuen Mutex erzeugen, damit die Anwendung nur einmal gestartet werden kann. System.Threading.Mutex appMutex = new System.Threading.Mutex(true, Application.ProductName, out createdNew); ///Wenn die Erzeugung erfolgreich war if (createdNew) { ///... dann kann die Anwendung ausgeführt werden LogIn frmLogIn = new LogIn(); Application.Run(frmLogIn);
if (frmLogIn.DialogResult == DialogResult.OK) Application.Run(new MainForm());
// den Mutex wieder frei geben appMutex.ReleaseMutex(); } else { ///Wenn die Anwendung schon ausgeführt wird -> Hinweis-Dialog string msg = String.Format("Das Programm \"{0}\" wurde bereits gestartet!", Application.ProductName); MessageBox.Show(msg, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); }
Das Core-Team von DotNetNuke hat in den letzten Versionen schon einiges an der Usability verbessert. Darunter gehört z.B. die Vererbung von Seiten-Rechten innerhalb der Seitenstruktur.
In vielen Projekten höre ich aber immer wieder, dass das ControlPanel (dort wo z.B. die Module ausgewählt werden) nicht flexibel genug ist und es Vorteilhaft wäre, wenn man anhand der DotNetNuke spez. Rollen die Funktionen ganz gezielt freischalten kann. Somit könnte man bestimmten Rollen ganz gezielt lediglich ein paar Module zur Verfügung stellen, die diese für ihre tägliche Arbeit benötigen. Der Vorteil liegt ganz klar auf der Hand: Die Komplexität für die Redaktuere wird reduziert. In vielen Fällen werden ja wirklich nur ganz wenige Module für die normale Arbeite benötigt (z.B.Text/HTML, Links, Images).
Seit ein paar Monaten verfolge ich eine Projekt, dass das DotNetNuke ControlPanel ersetzt (oder viel mehr eine Alternative bereit stellt). Mit diesem ControlPanel ist es nun endlich möglich die Berechtigungen innerhalb des Controlpanels sehr gezielt zu vergeben.
Hier kann man das Modul downloaden
Leider gibt es keine SourceCode Version von diesem Modul.
Gerade habe ich ein kostenloses eBook zum Thema Coding Guidlines für C# und VB.NET gefunden und möchte darauf aufmerksam machen.
Den Download gibt es direkt unter submain.com
Das eBook hat folgende Themen:
- Naming Guidelines
- Class Member Usage Guidelines
- Guidelines for Exposing Functionality to COM
- Error Raising & Handling Guidelines
- Array Usage Guidelines
- Operator Overloading Usage Guidelines
- Guidelines for Casting Types
- Common Design Patterns
- Callback Function Usage
- Time-Out Usage
- Security in Class Libraries
- Threading Design Guidelines
- Formatting Standards
- Commenting Code
- Code Reviews
- Additional Notes for VB .NET Developers
Ebenso recht nützlich ist das Tool SmartOutline for VS2005, welches als kostenlose Version auf der Seite zur Verfügung gestellt wird. Damit wird das Handling von #region's - welche ich sehr gerne benutze - noch etwas verbessert.
Im Augenblick beschäftige ich mich mit dem DNN NavigationProvider. um für einen Kunden ein CSS basiertes Menu zur Verfügung zu stellen. Ursprünglich dachte ich eigentlich, dass man auf das Rendern des Menüs Einfluß hat und bestimmen kann, wie das Menu auszusehen hat.
Nachdem ich den Sourcecode der mitgelieferten Provider analysiert habe .. kam zunächst recht schnell die Ernüchterung. Da wird in der class DNNMenuNavigationProvider auf eine Objekt vom Typ DNNMenu zugegriffen. Doch der Sourcecode scheint davon nicht mit im Standarddownload enthalten zu sein.
Mein erster Schreck - das ich das Rendern gar nicht beeinflussen kann - ging schnell vorbei. Zum einem ist natürlich die Klasse DNNMenu in dem Downloadpaket DotNetNuke WebControls enthalten und zum anderen ist die Nutzung dieses Objektes ja gar nicht notwendig.
Jetzt werde ich mal versuchen meinen eigenen Menuprovider zu entwicklen und bin gespannt wie das klappt!
Nachdem ich eigentlich schon wieder viel zu lange nichts mehr über DNN veröffentlicht hab, möchte ich damit nun endlich wieder beginnen.
Am 29.05 (also gestern) wurde die Version 4.5.2 veröffentlicht und steht wie gewohnt unter www.dotnetnuke.com zum Download bereit.
Mittlerweile ist eine ganze Menge an neuen Features implementiert wurden und eine einzelne Aufzählung wäre mit Sicherheit zu lang(weilig). Einen sehr genauen Einblick über die Veränderungen innerhalb von DotNetNuke bekommt man wie immer in der Bug Tracker.
Soeben habe ich ein sehr interessante Projekte oder viel mehr Komponente auf codeproject gesehen und möchte meiner Umwelt diese nicht vorenthalten.
Dabei handelt es sich jeweils um sehr schön gemachte Status List entwickelt in C#. Hier ist der direkte Link zu dieser .NET Komponente .... klick :)
Dazu passend gibt es auch noch ein Status Label (wohl in VB.NET) ... klick
Suchmaschinen wie www.google.de oder www.live.de sind für alle Entwickler - ob .NET, PHP, Delphi, etc. - ein wertvolles Werkzeug um schnell Antworten und Lösungen bei Problemem zu finden.
Das größte Problem dabei ist aber meist, dass man nicht nur Suchergebnisse bekommt dich sich auch wirklich mit .NET befassen und somit wird die Recherche unnötig erschwert. Dieses gehört aber der Vergangenheit an, denn Dan Appleman hat folgende Website erstellt:
http://www.searchdotnet.com/
Diese Suchmaschine basiert auf Google, allerdings werden wirklich nur .NET relevante Ergebnisse angezeigt.
Die ersten Erfahrungen mit dieer Suchmaschine waren sehr positiv!
Also ich mir gerade so ein wenig die Referrer angeschaut habe bzw. die Suchbegriffe inkl. Positionen bin ich über folgendes gestolpert:
In der Microsoft Live-Suche bin ich auf Platz 1 von 6 Millionen Treffer und das mit dem Begriff ".net 2.0".

Find ich persönlich schon ziemlich sexy und mein Tag ist gerettet :D
Die ASP.NET AJAX Extensions haben das Betastadium verlassen und sind nun RTW (Ready-to-Web). Diese Bibliothek integriert sich vollständig in das ASP.NET 2.0 Framework und liefert sowohl serverseitige Funktionalität als auch eine plattformübergreifend clientseitige JavaScript-Bibliothek. Dadurch soll es möglich sein auch bestehende Anwendungen mit minimalem Aufwand AJAX fähig zu machen.
Eine erste Anlaufstelle für AJAX ist die Website: http://ajax.asp.net/
Der direkte Downloadlink zur AJAX Extension ist hier.
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 :)
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.
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:)
Schon länger wollte ich mein Notebook mal mit Windows Vista ausstatten doch irgendwie fehlte mir die Zeit. Nachdem dann letzte Nacht mein Notebook softwaretechnisch zu Bode ging, habe ich mich direkt entschlossen Windows Vista zu installieren. Im guten Glauben gesagt, getan und dachte alles wäre gut! Doch weit gefehlt... der erste Eindruck ist echt gut (ein wenig gewöhnungsbedürftig aber ich würde sagen: nicht schlecht)....
Dann habe ich meine Visual Studio 2003 installiert, was kein Problem war, nur das Starten war mir nicht vergönnt. Was soll das denn ????
Eigentlich bin ich davon ausgegangen, dass Microsoft die meist verwendeten Anwendungen (Visual Studio 2003 / MS-SQL Server 2000, usw) unterstützt ... diese Hoffnung ist aber gerade wie eine Seifenblase geplatzt! Normalerweise bin ich nicht contra-microsoft aber das ist ja wohl komplett am Thema vorbei!
Sogar Visual Studio 2005 läuft nur nach einem ServicePack - und selbst dann gibt es wohl noch ein paar Probleme (mehr als unter XP). Super, toller Start in ein neues Betriebssystemzeitalter.... jetzt geht es wieder zum good, old Windowx XP - bis all meine Anwendung und Tools unter .NET 2.0 (3.0) laufen.
An dieser Stelle sage ich : Vielen Dank für nichts!
P.S.: Vielleicht hätten wir alle bei VB 6 bleiben sollen, denn das wird unter Vista supportet *mahlzeit*
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/
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 ..
Hier ein paar Blogbeträge zum Thema Barcodes und wie man diese unter DotNet erzeugen kann ohne 3rd-party Komponenten:
Wer schon mal HTML-E-Mails verschickt hat kommt wohl kaum um das Problem herum, dass man auch Bilder dieser E-Mail hinzufügen möchte. Der erste und einfachste Weg ist, diese einfach auf einem Server abzulegen und dann auf diesen zu verweisen. Was ist aber wenn der Anwender keine Internetverbindung hat, der Server bzw. das Bild nicht mehr erreichbar ist? Dann sehen diese E-Mails meist sehr unschön aus.
Gerade habe ich einen netten Artikel gefunden, der Beschreibt, wie man ein Bild als E-Mailanhang mitschickt und wie man die Verbindung zwischen Bild und Anhang herstellen kann.
Hier einmal die Kurzfassung:
<IMG height=68 src="cid:015024716@24012006-255A" width=140 align=top border=0>
Die Sourceanweisung mit dem Wert "cid:015024716@24012006-255A" ist hier das interessante. Die RFC-Spezi. besagt das jeder E-Mailanhang eine eindeutige Id bekommt.
Der benötigte Sourcecode zum Versand der E-Mail:
'Zu erst mal die Imports die benötigt werden Imports System.Net.Mail Imports System.Net.Mime
Public Sub SendMail()
Dim objMail As New MailMessage Dim objSender As New MailAddress("absender@server.de") Dim objSmtpClient As New SmtpClient("smtp.server.de:8881") Dim objEmpfaenger As New MailAddress("empfaenger@server.de")
objMail.To.Add(objEmpfaenger) objMail.From = objSender objMail.Subject = "Betreff der Mail"
'Damit das ganze auch funktioniert muss man angeben, 'das man die Mail im HTML-Format verschicken möchte objMail.IsBodyHtml = True
'So jetzt zum spannenden Teil, das Bild als Attachment anfügen Dim objFootImage As New Attachment(Server.MapPath("LOGO.gif"), _ MediaTypeNames.Image.Gif) objFootImage.ContentId = "01" objFootImage.ContentDisposition.Inline = True objFootImage.TransferEncoding = TransferEncoding.Base64 objMail.Attachments.Add(objFootImage)
'Und so wird es anschließend verwendet objMail.Body = "<img src=""cid:01"" border=0 height=68 width=140>"
'Jetzt nurnoch die Mail verschicken und fertig objSmtpClient.Send(objMail) End Sub
Eine ausführliche Erklärung des ganzen gibt es auf dieser Seite
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 ...
Mittlerweile gibt es viele XML-Editoren jetzt gibt es einen XML-Notepad :)
Das XML Team von Microsoft hat eine .NET 2.0 Anwendung released mit der man XML Documents bearbeiten kann, XSL supported, XML Schema Validierung und sogar ein XML Diff Tool... zu guter letzt gibt es sogar intellisense. Auch bei großen Dokumente ist die Performance der Anwendung gut und im Vergleich zu vielen anderen Editoren wirklich mal zu gebrauchen.
Den Download gibt es hier. Voraussetzung für das 2XML-Notepad" ist das .NET Framework 2.0.
Der erste Eindruck sieht echt gut aus, werde das jetzt mal in der Praxis vermehrt einsetzen.
Ich habe gerade eine coole Seite über Threading in .NET 2.0 gefunden, die auch viele Beispiele in C# bietet.
http://www.albahari.com/threading/
Zudem gibt es (derzeit links unten) einen PDF, das nun auf meinem "muss ich unbedingt mal komplett Lesen" Stappel liegt 
Auf CodePlex wird von Microsoft ein Projekt mit dem Namen Phalanger gehostet. Phalager soll einen PHP-Compiler anzubieten, der es ermöglicht, PHP-Skripts ohne Modifikation auf .NET zu kompilieren. Dabei erzeugt der Compilier aus PHP-Skipts MSIL (Microsoft Intermediate Language). Ausprobiert habe ich es selber noch nicht, allerdings finde ich den Ansatz sehr interessant!
Hier der direkte Link zum Projekt auf CodePlex
Gerade habe ich auf GotDotNet mal wieder eine wirklich coole Komponente gefunden, mit der man die Sidebar von Outlook 2003 abbilden kann.
Zu finden gibt es dieses .NET Komponenten - die übrigens in C# implementiert wurde - inkl. dem kompletten Sourcecode und einer Beispielanwendung, wie man die Komponente einsetzt, genau hier (klickst Du).
Eigentlich bin ich von den Controls des .NET Frameworks 2.0 sehr zufrieden und der Umfang der enthaltenen Controls ist durchaus brauchbar. Aber gerade bin ich doch ein wenig entäuscht, da es die Jungs wohl nicht geschafft, übersehen bzw. nicht an eine sehr simple doch oft gebraucht Funktionalität zu denken.
Ich habe eine Windowsforms-Anwendung auf der sich ein Multiline-Textfeld befindet. Jeder (oder sagen wir lieber viele) Benutzer sind es gewohnt den gesamte Inhalt eines solchen Textfeldes mit Strg-A zu markieren... doch was ist das? Nichts rührt sich, nichts wird markiert :(
Nach einer recherche im Web musste ich wohl feststellen, dass ich nicht zu blöd bin, sondern dieses Problem wohl auch bei anderen existiert. Also beleibt einem nichts übrig als diese Enterprise-Funktionalität selber zu implementieren... das würde dann so aussehen:
if ( (e.Control) && (e.KeyCode==Keys.A)) { this.myTextbox.SelectAll(); }
Mahlzeit!
Manchmal ist erwünscht, dass der Benutzer nur eine Instanze der Anwendung starten kann. Hier ein Code-Beispiel wie man dieses Verhalten über ein Mutex erreichen kann:
[STAThread] static void Main() { Application.EnableVisualStyles(); Application.DoEvents(); // ensure one instance running if(!MainForm.InstanceExists) { Application.Run(new MainForm()); } } static Mutex mutex; static string AppGuid = "4B3DF7C2-1BD3-7d54-AFF0-A3D4656C5EDH"; static bool InstanceExists { get { bool notExists; mutex = new Mutex( false, "Local\\" + AppGuid, out notExists ); return !notExists; } }
Durch die Verwendung einer Guid wird hier die "Einmaligkeit" gewährleistet. Sollte die Anwendung auf einem Terminalserver laufen dann muss "Local\\" gegen "Global\\" ersetzt werden....
In .NET 2.0 ist das Arbeiten mit Threads dank des Backgroundworkers deutlich einfacher geworden. Heute Abend habe ich mich mal damit beschäftigt in einem Backgroundworker einen Treeview zu füllen. Der Zugriff auf ein Control in der Methode DoWork() ist nämlich nicht möglich, aber es gibt einen Trick, dieses zu lösen.
Zunächst einmal die Basics um einen Backgroundworker bereitzustellen:
this.backgroundworker = new BackgroundWorker(); this.backgroundworker.WorkerReportsProgress = true; this.backgroundworker.DoWork += new DoWorkEventHandler(backgroundworker_DoWork); this.backgroundworker.ProgressChanged += new ProgressChangedEventHandler(backgroundworker_ProgressChanged); this.backgroundworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundworker_RunWorkerCompleted);
Wichtig dabei ist lediglich das Event ProgressChanged zu implementieren und die Property WorkerReportsProgress auf "true" zu setzen. Bis hier noch nicht wirklich aufregend....auch der Auruf mit
this.backgroundworker.RunWorkerAsync();
ist wie gewohnt.
In der Methode DoWork() kommt dann aber der Trick...
void backgroundworker_DoWork(object sender, DoWorkEventArgs e) {
TreeNode treenode= new TreeNode(); treenode.Text = 'name'; this.backgroundworker.ReportProgress(0, treenode); }
Hier jetzt einfach mal so viel Vorstellungskraft aufbringen als würde DoWork() eine Schleife, Datenbankabfrage oder ähnliches durchführen, die viel Zeit in Anspruch nimmt. Die Möglichkeit eine Fortschritt zu Reporten kann man nun nutzen um ein Object an eine Form weiterzugeben. Die Implementierung der Methode/Event ProgessChanged könnte dann so aussehen:
void backgroundworker_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.tvNavigator.BeginUpdate(); this.tvNavigator.Nodes.Clear(); this.tvNavigator.Nodes.Add((TreeNode)e.UserState); this.tvNavigator.EndUpdate(); }
Mit diesem Trick ist es nun möglich einen TreeView asyncron zu füllen....
Eine wirklich sehr coole Vorstellung der WCF (Windows Communication Foundation) gibt es derzeit als Folge von dotnetPro-TV. Zusammen mit Ralf Westphal gibt Christian Weyer einen super Überblick für Einsteiger und Neulinge in diesem Bereich.
Derzeit gibt es das Video sogar für die Öffentlichkeit zugänglich auf der Seite von DotNetPro, der Link zum Video ist in der orangefarbenen Kästchen.
Viel Spaß :)
Wer mal "eben" ein Regex-Pattern erstellen möchte und dieses auch direkt testen will, kann ein kleines Online-Tool dafür nutzen. Hier der Link
Ich kann es ja kaum glauben aber bei dem mächtigen Framework von .Net wird es echt kompliziert eine DateTime Wert von GMT in PST zu konvertieren. Habe gerade ein paar lustige Stunden damit verbraucht eine dieses einigermaßen sauber zu implementieren und hier meine Lösung:
Basis für meine Lösung ist eine Klasse von Clemens Vasters und seiner Blogengine dasblog.net. Dort gibt es im Projekt "newtelligence.DasBlog.Util.csproj" die Klasse "TimeZones.cs". Die nötigen Informationen für eine Konvertierung wird hier allerdings in einer XML Datei gespeichert. Da ich derzeit allerdings nur eine konvertierung nach PST brauch habe ich die XML Datei ignoriert und setze die Daten manuell in einer Klasse.
/// <summary> /// Liefert verschiedne Zeiten auf der Welt zurücl /// </summary> public class TimeZoneConverter {
/// <summary> /// (GMT-08:00) Pacific Time (US & Canada); Tijuana /// Pacific Daylight Time /// </summary> /// <returns>DateTime of Pacific Daylight Time</returns> public static DateTime GetCurrentPST() { return DateTime2PST(DateTime.Now) ; }
/// <summary> /// (GMT-08:00) Pacific Time (US & Canada); Tijuana /// Pacific Daylight Time /// </summary> /// <returns>DateTime of Pacific Daylight Time</returns> public static DateTime DateTime2PST(DateTime dtDate) {
WindowsTZI pstTZI = new WindowsTZI(); pstTZI.bias = 480; pstTZI.daylightBias = -60; pstTZI.standardBias = 0; WindowsSystemTime standardDate = new WindowsSystemTime(); standardDate.year = 0; standardDate.month = 10; standardDate.day = 5; standardDate.dayOfWeek = 0; standardDate.hour = 2; standardDate.minute = 0; standardDate.second = 0; standardDate.milliseconds = 0;
WindowsSystemTime daylightDate = new WindowsSystemTime(); daylightDate.year = 0; daylightDate.month = 4; daylightDate.day = 1; daylightDate.dayOfWeek = 0; daylightDate.hour = 2; daylightDate.minute = 0; daylightDate.second = 0; daylightDate.milliseconds = 0;
pstTZI.standardDate = standardDate; pstTZI.daylightDate = daylightDate;
WindowsTimeZone tz = new WindowsTimeZone(); tz.WinTZI = pstTZI; return tz.ToLocalTime ( dtDate.ToUniversalTime() ) ;
}
}
Wer das ganze etwas dynamischer haben möchte schaut sich am beste die Klasse vom Clemens an ...
Ich brauchte diese Funktion für die Google-Adwords-API, diese erwatet nämlich das Datum im PST Format.
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.Path Dim sSeparator As String = "?" Dim sKey As String For Each sKey In nvc If sKey <> Nothing Then Dim sValues As String() = nvc.GetValues(sKey) Dim sValue As String For Each sValue In sValues If sValue <> Nothing Then strNewURL &= sSeparator strNewURL &= sKey & "=" & sValue sSeparator = "&" End If Next End If Next If nvc.Keys.Count < 1 Then strNewURL &= "?" End If http_Context.Current.RewritePath(strNewURL) End Sub
Gefunden habe ich den Code unter http://www.codeproject.com
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(); }
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.
Die ersten Erfahrungen mit dem .NET Framework 2.0 waren sehr erfreulich. Als eines der ersten Features habe ich mir die "Anwendungseinstellungen" vorgenommen und war total begeistert. Endlich wird einem diese lästige Aufgabe komplett abgenommen auch das Binden von Einstellunge auf Eigenschaften eines Controls finde ich super! Nur noch ein Load() und Save() in den Code einbauen und fertig. So dachte ich zumindest aber der Frust kam relativ schnell:
Das Speichern von benutzerabhängigen Einstellungen wird unter c:\Dokumente und Einstellungen\benutzername\.... vorgenommen. So weit kein Problem nur das die Versionsnummer mit im Pfad stehen muss finde ich richtig übel. So bald sich die Versionnummer ändert ist es mit den alten Einstellungen essig ... es gibt zwar eine Upgrade() Methode aber bei der Verwendung von SettingKey funktioniert das nicht mehr :(
Also habe ich versucht den Pfad anzupassen und habe gegoogelt .. siehe da: Es geht nicht .... super gemacht, toll durchdacht aber dann trotzdem leider auf den letzten Metern versaut. Immerhin hat man die Möglichkeit einen eigenenen Provider zu schreiben, um die Einstellungen abzuspeichern. Das wiederum ist klasse gelöst und mehr als sinnvoll!
Nun hier ist eine Provider, der die Einstellungen im XML-Format unter dem Anwendungsverzeichnis speichert:
using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Configuration; using System.Windows.Forms; using System.Xml; using System.Collections.Specialized; using Microsoft.Win32;
namespace GaliNeo.Framework.GaliNeoSettings { class GaliNeoSettingsProvider : SettingsProvider { XmlDocument doc = null; XmlNode root = null; XmlNode userSettings = null; XmlNode appSettings = null;
public GaliNeoSettingsProvider() { doc = new XmlDocument(); LoadSettings(); }
public override string ApplicationName { get { return Application.ProductName; } set { } }
public override void Initialize(string name, NameValueCollection col) { base.Initialize(this.ApplicationName, col); }
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals) {
foreach (SettingsPropertyValue propval in propvals) {
SettingsProperty prop = propval.Property;
setValue(prop, propval, context);
}
this.WriteSettings(); }
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props) {
// Create new collection of values SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); string sectionName = this.GetSectionName(context); string settingKey = (string)context["SettingsKey"];
// Iterate through the settings to be retrieved foreach (SettingsProperty setting in props) { SettingsPropertyValue value = new SettingsPropertyValue(setting); value.IsDirty = false; value.SerializedValue = getValue(setting, context );
values.Add(value); } return values;
}
private XmlNode SerializeToXmlElement(SettingsProperty setting, SettingsPropertyValue value) {
XmlElement element = doc.CreateElement("value"); string text1 = value.SerializedValue as string; if ((text1 == null) && (setting.SerializeAs == SettingsSerializeAs.Binary)) { byte[] buffer1 = value.SerializedValue as byte[]; if (buffer1 != null) { text1 = Convert.ToBase64String(buffer1); } } if (text1 == null) { text1 = string.Empty; } if (setting.SerializeAs == SettingsSerializeAs.String) { //text1 = this.Escaper.Escape(text1); }
element.InnerXml = text1; XmlNode node1 = null; foreach (XmlNode node2 in element.ChildNodes) { if (node2.NodeType == XmlNodeType.XmlDeclaration) { node1 = node2; break; } } if (node1 != null) { element.RemoveChild(node1); } return element; }
private string GetSectionName(SettingsContext context) { string groupName = (string)context["GroupName"]; string settingKey = (string)context["SettingsKey"]; string section = groupName; if (!string.IsNullOrEmpty(settingKey)) { object[] arrName = new object[] { section, settingKey }; section = string.Format("{0}.{1}", arrName); } return XmlConvert.EncodeLocalName(section); }
#region DAN
private string getXPathQueryProperty(SettingsProperty setting, SettingsContext context) { string xPathQuery = getXPathQuerySection(setting, context);
if (setting.Name != "") { xPathQuery += "/" + setting.Name; } //if (propName != "")
return xPathQuery; }
private string getXPathQuerySection(SettingsProperty setting, SettingsContext context) { string xPathQueryGroup = doc.DocumentElement.LocalName ;
if (this.IsUserScoped(setting)) { xPathQueryGroup += "/userSettings"; } else { xPathQueryGroup += "/appSettings"; } xPathQueryGroup += "/" + GetSectionName(context);
return xPathQueryGroup;
}
private void CreatePropNode(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context) { string xPathQuery = getXPathQuerySection(setting, context);
XmlNode groupNode = doc.SelectSingleNode(xPathQuery);
if (groupNode == null) { groupNode = doc.CreateElement(GetSectionName(context));
if (this.IsUserScoped(setting)) { userSettings.AppendChild(groupNode); } else { appSettings.AppendChild(groupNode); }
} //if (node == null)
XmlNode nodeProp = doc.CreateElement(setting.Name);
nodeProp.AppendChild (this.SerializeToXmlElement(setting,value) );
groupNode.AppendChild(nodeProp);
}
private void setValue(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context) //string propName, string groupName, object value, object defaultvalue) {
string xPathQuery = getXPathQueryProperty(setting,context);
XmlNode node = doc.SelectSingleNode(xPathQuery); if (node != null) { XmlNode valueNode = SerializeToXmlElement(setting, value); node.RemoveAll(); node.AppendChild(valueNode); } else {
CreatePropNode(setting, value, context);
} //if (node != null)
}
private object getValue(SettingsProperty setting, SettingsContext context) { string xPathQuery = getXPathQueryProperty(setting, context);
XmlNode node = doc.SelectSingleNode(xPathQuery + "/value");
if (node != null) { return node.InnerXml; } else if (setting.DefaultValue != null) { return setting.DefaultValue; } else { return null; }
}
// Helper method: walks the "attribute bag" for a given property // to determine if it is user-scoped or not. // Note that this provider does not enforce other rules, such as // - unknown attributes // - improper attribute combinations (e.g. both user and app - this implementation // would say true for user-scoped regardless of existence of app-scoped) private bool IsUserScoped(SettingsProperty prop) { foreach (DictionaryEntry d in prop.Attributes) { Attribute a = (Attribute)d.Value; if (a.GetType() == typeof(UserScopedSettingAttribute)) return true; } return false; }
#endregion
private void LoadSettings() { string configFile = getPath() + "user.config";
if (System.IO.File.Exists(configFile) ) { doc.Load(configFile); root = doc.DocumentElement; userSettings = doc.DocumentElement.SelectSingleNode("./userSettings"); appSettings = doc.DocumentElement.SelectSingleNode("./appSettings"); ;
} else {
try { root = doc.CreateElement("configuration");
userSettings = doc.CreateElement("userSettings"); root.AppendChild(userSettings); appSettings = doc.CreateElement("appSettings"); root.AppendChild(appSettings);
doc.AppendChild(root); } catch {
} }
}
private string getPath() { return Application.StartupPath + @"\App_Data\" ; }
private void WriteSettings() { if (!( System.IO.Directory.Exists(getPath()))) { System.IO.Directory.CreateDirectory(getPath()); } string configFile = getPath() + "user.config";
doc.Save(configFile);
}
} }
Nun das ist noch nicht 100% best practice Entwicklung (musste schnell gehen) aber es funktioniert ....:)
Ab Heute wird die Thematik dieses Blogs ein wenig erweitert. Nun ist es endlich so weit und di Entwicklung mit .NET 2.0 geht bei mir endlich los. In der nächsten Zeit wird der Schwerpunkt mehr auf .NET Winforms und der Google-API liegen.
Aber keine Angst ich werde DotNetNuke nicht wirklich vernachlässigen.
|