Seit heute gibt es auf der Connect-Site von Microsoft die CTP-Version von VS 2010 und .NET 4.0 download. Ich denke, ich werde bestimmt auch bald die Installation auf mich nehmen.
Montag, Oktober 27, 2008
Visual Studio 2010 und .NET 4.0 download
Eingestellt von
Jan Zieschang
um
22:26
0
Kommentare
Tags: dev
Sonntag, Oktober 26, 2008
Upgrade zu ASP.NET MVC Beta
Ich habe mich heute an das Upgrade meiner ASP.NET MVC Applikation auf die Beta-Version gestürzt. Mit dem Beta-Status ist die MVC-API als relativ stabil zu bezeichnen, so dass mit der nächsten und ggf. übernächsten Version kaum Änderungen zu erwarten sind.
Den Anfang der heutigen Aktion machte der Download des Beta-Releases und anschließend der Download des Future-Assembly. (Im Zweifel beides immer über Codeplex ASP.NET zu erreichen)
Der nächste Schritt war das lesen des Blog-Posts von ScottGu, so dass man wieder auf dem Laufendem ist. Allerdings sind soviele neue Features drin, die ich nicht wirklich nutzen kann/will. Einiges ist sehr cool, aber deutlich zu spät für mich.
Als erstes mussten alle Namespaces in der Config angepasst werden. Es kommen 2 neue Namespaces hinzu:
- <add namespace="System.Web.Mvc.Ajax"/>
- <add namespace="System.Web.Mvc.Html"/>
Anschließend musste die Html.Form<>-Helper aufrufe umgeschrieben werden, allerdings zum Glück nur durch die Methode Html.BeginForm<> zu ersetzen. Doch Achtung, die Generic-Versionen sind nur im Future-Assembly zu finden. Ist dieses nicht referenziert, so wird die Methode nicht gefunden.
Der 3. Knackpunkt, der mich kurz aus der Bahn geworfen hat, war eine Änderung am OutputCaching. Dieses muss genau die gleiche Angaben enthalten, wie es bei der Page-Direktive notwendig ist. ([OutputCache(Duration=20, VaryByParam=*)] oder [OutputCache(Duration=20, VaryByParam=none)])
Anschließend war "alles" schick und es lief wieder. Zumindest sind mir derzeit keinerlei weitere Probleme entgegen gekommen.
Eingestellt von
Jan Zieschang
um
20:18
0
Kommentare
Tags: ASP.NET
Sonntag, Oktober 19, 2008
WCF Project Layout
Für das Layout von WCF-Projektstrukturen gibt es relative klare Empfehlungen, leider sind die in den Visual Studio Templates nicht abgebildet. Im Gegenteil, es wird von vielen Architekten und Entwicklern im WCF-Umfeld empfohlen, komplett auf diese Templates zu unterstützen. Es wird einfach zu viel gemacht, dass gar nicht notwendig ist und das eine saubere Trennung erschwert. Die Empfehlung für WCF-Projekte sieht vor, dass Contracts, egal ob Data- oder ServiceContract[s] in einem separaten Assembly (Class-Library) abgelegt werden. Die Implementierung der Services und weiterer Schichten kann dann, wie bei WebService oder anderen Projekten durchgeführt werden.
Assemblies:
- Contract
- Service (evtl. als Facade), ggf. als IIS-Projekt
- Datalayer
Oft wird auch oft empfohlen, dass man eine Fassaden-Architektur einzieht, wobei dass sehr umstritten ist. In der Fassade wird die spezielle Behandlung von FaultContract(s) durchgeführt, Artikel zu WCF-Exception Handling "Exception Handling in WCF using Fault Contract". Außerdem kann man die Fassade sehr gut dazu benutzen, Exception-Informationen von der Außenwelt zu verbergen.
Sind die Contracts sauber in dem separatem Assembly programmiert, kann dieses Assembly in .NET-Clients verwendet werden. Dadurch spart man sich die "hässliche" Generierung von Services auf dem Client. In allen Projekten, die ich durchgeführt habe, hat sich das als der beste Weg herausgestellt. Allerdings ist darauf zu achten, dass nur ein Vertrag in dem Assembly eingeführt wird. Die Implementierung von Logik hat in den Verträgen nichts zu suchen und würde die Unabhängigkeit von Client und Service verhindern. Ist das der Fall, hat man eine bessere .NET Remoting Lösung erstellt. Nur noch einmal zur Klarstellung, dass Contract-Assembly muss nicht genutzt werden, aber es ist sauberer für .NET Clients.
Eingestellt von
Jan Zieschang
um
21:10
0
Kommentare
Sonntag, Oktober 05, 2008
ASP.NET Ajax: Scripte zusammenfassen
Ich bin etwas spät, aber bevor ich es niemals mehr blogge kommt heute der Artikel zu JS. Ich habe mir endlich mal wieder Zeit für das Bloggen genommen und bin auch froh. Meine Arbeitslage hat sich sehr plötzlich etwas entspannt.
Der ScriptManager aus dem .NET Framework 3.5 kann JavaScripte auf dem Server zusammenfassen. Das bedeutet, dass eine Anzahl von Scripten in ein größeres Script zusammengefasst wird. Es gibt mehrere Vorteile, die durch das zusammenfassen entstehen:
- weniger Server-Roundtrips für den Download der Script
- optimierte Script-Files (entfernte Kommentare, entfernte Zeilenumbrüche)
Das schwierige für das Zusammenfassen von Scripten ist allerdings herauszubekommen, was alles geladen werden muss. Hierfür existiert allerdings auch ein passendes Tools, mittels dem der Konfigurationsblock sehr einfach erzeugt werden kann. Der ScriptReferenceProfiler ist ein Server-Control, dass einfach auf der Webseite eingebunden wird. Beim Aufruf der Webseite erhählt man einen Script-Block als Ausgabe. Der Script-Block wird 1:1 in die ASP.NET-Seite eingefügt und zwar beim eingebundenen Script-Manager. Eine sehr gute Anleitung kann unter video-296.aspx angeschaut werden.
Ursprünglich eingebundener ScriptManager:
<asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager>
Eingefügte Scripte, die zusammengefasst werden:
<asp:ScriptManager ID="ScriptManager1" runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference Name="MicrosoftAjax.js" /> <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" /> <asp:ScriptReference Name="”AjaxControlToolkit.Common.Common.js”" Assembly="”AjaxControlToolkit," Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" /> <asp:ScriptReference Name="”AjaxControlToolkit.ExtenderBase.BaseScripts.js”" Assembly="”AjaxControlToolkit," Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" /> </Scripts> </CompositeScript> </asp:ScriptManager>
Eigentlich ist das alles super einfach, allerdings kann es passieren, dass durch sehr viele Scripte die URL zu lang wird. Als Fehler kommt die Meldung "The resource URL cannot be longer than 1024 characters. If using a CompositeScriptReference, reduce the number of ScriptReferences it contains, or combine them into a single static file and set the Path property to the location of it." Das ganze hört sich wesentlich dramatischer an, als es ist. Um das Problem zu lösen, muss man die Scripte aufteilen. Dazu werden ScriptManagerProxy-Controls verwendet. Die Proxy-Instanzen sind ursprünglich für die Verwendung auf Unterseiten gedacht, um weitere Scripte oder Services einzufügen.
<asp:ScriptManager ID="ScriptManager1" runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference Name="MicrosoftAjax.js" /> <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" /> </Scripts> </CompositeScript> </asp:ScriptManager> <asp:ScriptManagerProxy ID="proxy1" runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference Name="”AjaxControlToolkit.Common.Common.js”" Assembly="”AjaxControlToolkit," Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" /> <asp:ScriptReference Name="”AjaxControlToolkit.ExtenderBase.BaseScripts.js”" Assembly="”AjaxControlToolkit," Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" /> </Scripts> </CompositeScript> </asp:ScriptManagerProxy>
Ein sehr guter Artikel zu dem Thema wurde von Samir Bellouti geschrieben.
Eingestellt von
Jan Zieschang
um
15:54
0
Kommentare
Dienstag, September 09, 2008
ASP.NET MVC Preview 5 - Arrrggghhh
An diesem Wochenende war nun wirklich mal wieder beschäftigen mit ASP.NET MVC dran, das Preview 5 wollte ich natürlich nicht länger hinaus schieben, also wurde das installiert. Vorher habe ich die Release Notes studiert, ob es etwas gibt, dass bei mir Probleme machen könnte. Eigentlich sollte die Migration von Preview 4 nach Preview 5 ohne Komplikationen verlaufen, dachte ich. Übrigens eine nette Übersicht über die Änderungen gibt es unter http://www.coderjournal.com/2008/08/aspnet-mvc-preview-release-5/.
Ich habe den halben Tag damit zugebracht nur eine kleine Funktion in meiner Anwendung zu fixen, allerdings war das mehr Arbeit als ich dachte. Die "Html.RenderUserControl" wurde aus dem Html-Helper entfernt, allerdings ohne Kommentar und Ersetzungsempfehlung. Ein UserConrol kann über den klassischen Weg mit Register und anschließend hinzufügen auf der Seite einbinden. Was macht man allerdings mit den Daten und die Parameter, die alle übergeben wurden. Nunja, ein UserControl habe ich über den klassischen Weg abgebildet, doch die anderen .... Also der Klassiker googlen, ich bin mit Sicherheit nicht der einzige, der auf diese Problem gestoßen ist. Die beste Hilfe war das ASP.NET Forum, in dem wenigstens einer auch den Lösungsweg aufzeigte. Letztendlich muss man sein Control und den Aufruf umschreiben. Bei der Verwendung der RenderPartial-Methode können nicht die Parameter die Control-View als AnonymousType übergeben werden. Ich habe meine Lösung anschließend so angepasst, dass alle Parameter in den Model-Daten übergeben werden und mittels der Eval-Methode extrahiert werden. Der Aufwand war schon recht groß, nun bin ich erstmal froh, dass alles funktioniert.
Wichtig ist bei der Umstellung auf das Preview 5 die Versionsnummern in der web.config entsprechend den Release Notes anzupassen, da durch das Final-Release des SP1 einige Versionsnummern final sind und zu dem auch noch niedriger als in den Test-Builds.
Außerdem muss man bei den ErrorHandler-Attribute aufpassen. Man muss CustomErrors in der Konfiguration aktivieren, damit der ErrorHandler arbeitet, andernfalls werden die Fehlerdetails ausgegeben.
Eingestellt von
Jan Zieschang
um
21:03
0
Kommentare
Dienstag, September 02, 2008
Lost in Work, But still alive
Der letzte Post ist schon verdammt lange her und wenn ich mal den kurzen Beitrag zum SP1 herauslasse, dann ist inzwischen fast 1 Monat vergangen. Ich bin die Tage einfach nicht zum bloggen gekommen, nach 10+h auf Arbeit inkl. Wochenende, hatte ich einfach keine Kraft/Lust mehr zum bloggen. Ich konnte auch kaum Themen neben der Arbeit angehen, geschweige denn die Wohnung aufräumen. Der große hektische Brocken ist geschafft, jetzt droht "nur" das übliche Kundengeschäft. Ich habe jetzt wieder Zeit viel Zeit an jemanden zu denken. Es fällt mir noch immer schwer, wie dumm!
Letzten Monat haben ein Kollege und ich, partiell mit weiterer Unterstützung, einen Prototypen für eine Tourenanwendung auf Basis von SCSF erstellt. Wie der Prototyp angekommen ist, habe ich leider noch nicht erfahren, ich hoffe, dass die Arbeit sich gelohnt hat und entsprechend auch in weitere Entwicklungsarbeit endet. Geklärt ist die Aufwandsentschädigung noch nicht, aber ich gehe davon aus, dass sich das Thema in den nächsten Tage/Wochen klärt.
Der Ausblick auf meine Projekteinsätze sieht jetzt schon extrem schlecht aus. Zumindest richtig schlecht, wenn die Kunden alle "Drohungen" wahr machen und entsprechend beauftragen. Aus irgendeinem Grund gibt es noch kein Klonen. Aber andererseits würde das bei mir auch nicht helfen, da dann 2 herumrennen würden, die die gleiche Frau vermissen.
Meine ursprüngliche Überlegung war mal den Urlaub im September abzufackeln, aber daraus wird mit Sicherheit nichts mehr. Bisschen frage ich mich, ob dieses Jahr noch der Urlaub unter zu bekommen ist. Vermutlich muss ich darüber mit meiner GF reden, denn verfallen lassen will ich den Urlaub nicht.
Ich muss mich in der nächsten Zeit mal wieder auf mein MVC-Projekt stürzen, da dieses für meine Ziele enorm wichtig ist. Außerdem ist damit der Umstieg auf die neuen Versionen von Trac und SVN verbunden, bei beiden Projekten gibt es super Interessante Features, die ich einsetzen möchte.
Das nächste Thema, in das ich mich endlich mal einarbeiten möchte ist WPF und Composite WPF. Ich bin so gespannt, wie sich die Performance im Vergleich zu SCSF sich verhält.
Eingestellt von
Jan Zieschang
um
08:19
0
Kommentare
Tags: privates
Montag, September 01, 2008
ASP.NET MVC Preview 5
Am Wochenende wurde vom MVC-Projektteam das PR5 veröffentlicht!
Etwas überrascht war ich im August, dass das MVC nicht Bestandteil des Frameworks wurde. Ich habe eigentlich stark gehofft, allerdings wäre der Zeitplan extrem sportlich geworden. Nun ja, ich find es wiederum auch gut, dass lieber die Qualität stimmen musste, bevor man das Fx v
eröffentlicht.
Ich bin noch nicht zur Umstellung meiner Version gekommen, hoffe allerdings das es diesmal weniger Probleme gibt, als beim letzten mal. Da habe ich 2 Tage zum Modifizieren und Testen benötigt. Bin gespannt auf die Posts zu den aktuellen Themen von Phil und Scott. Evtl. geht es auch mit der Screencast Serie weiter.
Download: http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16775
Eingestellt von
Jan Zieschang
um
09:54
0
Kommentare
Dienstag, August 12, 2008
.NET Framework SP1 und Visual Studio Service Pack 1 Released
Endlich gibt es die beiden Service Packs zum download. Alle Informationen sind sehr gut über diese Link verfügbar Visual Studio 2008 SP1 and .NET 3.5 SP1 Release to Manufacturing.
Der Download ist wirklich gewaltig, Visual Studio SP1 sind mal eben 800MB dazu kommt noch das TFS Service Pack 1 und .NET Framework.
Ich werde in den nächsten Tage meine aktuellen VMs anpassen und alle notwendigen Installationen durchführen.
Schnell noch einige Snapshots machen! ...
Eingestellt von
Jan Zieschang
um
08:51
0
Kommentare
Tags: dev
Sonntag, August 03, 2008
Windows PerformanceCounter Komponente
In der letzten Woche habe ich mich gleich in 2 Projekten mit Windows Performance Countern beschäftigt. Das war nicht das erste mal, so dass mir dabei auch aufgefallen ist, dass in einer früheren Implementierung von mir eine Reihe von Fehlern waren.
Allgemeines
Mittels Performance Countern kann man sehr gut Leistungsdaten eines Server/Anwendung erfassen und protokollieren. Man kann damit zum Beispiel die Anzahl der Aufrufe auf einen Dienst/Webservice/Layer verfolgen oder die Laufzeit. Es gibt wahnsinnig viele interessante Indikatoren in einer Anwendung. Performance Counter sind ebenso extrem wichtig, wenn mit Monitoring Software eine Anwendung überwacht wird. Sehr interessant für die Verwaltung und Administration von Servern ist auch die Möglichkeit Alarme zu definieren. Einen sehr netten Artikel zum Thema Andrew Z. Tabona Windows 2003 Performance Counter.
Coding
Ich wollte eine Komponente erstellen, die von jeder beliebigen Klasse und große Kenntnisse genutzt werden kann. Leider ist es nicht möglich einfach zu sagen, dass man jetzt in Ziel X etwas ausgeben will. Performance Counter müssen vor der Benutzung angelegt werden, zu dem sind für erhöhte Rechte notwendig. Aber Schritt für Schritt:
Prinzipiell ist das Schreiben von Performance-Counter-Werten sehr einfach.
1 PerformanceCounter c = new PerformanceCounter("myCategory", "CountCalls",false)
2 c.Increment();
3 c.Decrement();
4 c.IncrementBy(5);
Allerdings muss vorher sichergestellt sein, dass der Counter existiert und zugegriffen werden kann. Da Counter immer auch einer Category zugeordnet sind, muss diese ebenso angegeben werden.
1 CounterCreationDataCollection creation = new CounterCreationDataCollection();
2 creation.Add(new CounterCreationData(c.CounterName, c.CounterHelp, c.CounterType));
3 PerformanceCounterCategory.Create(category, "", PerformanceCounterCategoryType.Unknown, creation);
Beim Anlegen eines Counters hat man immer die Wahl, ob ein Multi-Instanz Counter oder ein Single-Instanz Counter angelegt wird. Die Idee dahinter ist relativ simpel. Jede Applikation/Komponente kann bei einem Multi-Instanz Counter verfolgt werden, entsprechend werden für alle Einträge erzeugt. Bei einem Single Instanz Counter werden alle Log-Informationen für den gesamten Server protokolliert. Eine Differenzierung wäre in dem Fall nicht möglich, aber auch nicht immer sinnvoll.
Wird ein Counter vom Typ "PerformanceCounterType.AverageTimer32" angelegt, so muss zusätzlich auch der BaseCounter "PerformanceCounterType.AverageBase" angelegt werden, da es sonst zu Fehler kommt. Bei der Verwendung des Counters soll man die StartZeit in Ticks - der Endzeit der Aktion angeben, ehrlich gesagt, ich habe es noch nicht 100% verifiziert, ob der Counter richtig funktioniert. Ich nutze am meisten den einfachen Zähler oder Aufrufe pro Sekunde.
ABER, ist eine Category angelegt, kann man keine Counter hinzufügen, zumindest nicht mit Managed Code, ich kenne auch keinen anderen Weg, evtl. ist dies über Registry-Manipulation möglich. Aus diesem Grund muss die Category immer gelöscht werden, wenn ein Counter zu der Category hinzugefügt wird. Anschließend werden alle Counter erneut hinzugefügt.
Nach soviel Kleinigkeiten, hier mal ein ganzer Code-Block:
63 private static readonly IDictionary<string, IDictionary<string, PerformanceCounter>> categoryDict =
64 new Dictionary<string, IDictionary<string, PerformanceCounter>>();
65 private PerformanceCounter GetCounter(string category, string counterName, bool useInstance, PerformanceCounterType type)
66 {
67 if (string.IsNullOrEmpty(category) || string.IsNullOrEmpty(counterName))
68 return null;
69 try
70 {
71 return EnsureWithCategory(category, counterName, useInstance, type, false);
72 }
73 catch (Exception ex)
74 {
75 System.Diagnostics.Trace.WriteLine("Get counter failed! " + ex.ToString(), "EnterpriseLoggingService.GetCounter");
76 }
77 return null;
78 }
79 private static ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
80
81 private PerformanceCounter EnsureWithCategory(string category, string counterName, bool useInstance, PerformanceCounterType type, bool deep)
82 {
83 PerformanceCounter counter;
84 cacheLock.EnterUpgradeableReadLock();
85 try
86 {
87 if (categoryDict.ContainsKey(category))
88 {
89 IDictionary<string, PerformanceCounter> perf = categoryDict[category];
90 return EnsureCounter(category, counterName, useInstance, type, perf);
91 }
92 else
93 {
94 if (deep)
95 return null;
96 return EnsureCounter(category, counterName, useInstance, type, null);
97
98 }
99
100 }
101 finally
102 {
103 cacheLock.ExitUpgradeableReadLock();
104 }
105 }
106
107 private static PerformanceCounter EnsureCounter(string category, string counterName, bool useInstance, PerformanceCounterType type, IDictionary<string, PerformanceCounter> perf)
108 {
109 PerformanceCounter counter;
110 if (perf != null && perf.ContainsKey(counterName))
111 {
112 counter = perf[counterName];
113 }
114 else
115 {
116 cacheLock.EnterWriteLock();
117 try
118 {
119 bool exists = false;
120 Dictionary<string, PerformanceCounter> counterDict;
121 CounterCreationDataCollection creation = new CounterCreationDataCollection();
122 if (PerformanceCounterCategory.Exists(category))
123 {
124 exists = PerformanceCounterCategory.CounterExists(counterName, category);
125 PerformanceCounterCategory pc = new PerformanceCounterCategory(category);
126 PerformanceCounter[] counters;
127 if (pc.CategoryType == PerformanceCounterCategoryType.MultiInstance)
128 counters = pc.GetCounters(AppDomain.CurrentDomain.FriendlyName);
129 else
130 counters = pc.GetCounters();
131
132 foreach (PerformanceCounter c in counters)
133 {
134 creation.Add(new CounterCreationData(c.CounterName, c.CounterHelp, c.CounterType));
135 }
136 if (!exists)
137 {
138 if (perf != null)
139 {
140 foreach (PerformanceCounter p in perf.Values)
141 {
142 p.Dispose();
143 }
144 perf.Clear();
145 perf = null;
146 }
147 PerformanceCounterCategory.Delete(category);
148 }
149 }
150 if (!exists)
151 {
152 creation.Add(new CounterCreationData(counterName, "", type));
153 if (type == PerformanceCounterType.AverageTimer32)
154 creation.Add(new CounterCreationData(counterName + "Base", "", PerformanceCounterType.AverageBase));
155 PerformanceCounterCategory.Create(category, "", PerformanceCounterCategoryType.Unknown, creation);
156 }
157 counterDict = new Dictionary<string, PerformanceCounter>(creation.Count);
158 foreach (CounterCreationData ccd in creation)
159 {
160 counter = new PerformanceCounter(category, ccd.CounterName, useInstance ? AppDomain.CurrentDomain.FriendlyName : "", false);
161 counterDict.Add(ccd.CounterName, counter);
162 }
163 counter = counterDict[counterName];
164 perf = counterDict;
165 if (categoryDict.ContainsKey(category))
166 categoryDict[category] = counterDict;
167 else
168 categoryDict.Add(category, counterDict);
169 }
170 finally
171 {
172 cacheLock.ExitWriteLock();
173 }
174 }
175 return counter;
176 }
177 public void NumberCounter(string category, string counterName, bool useInstance, int incrementValue)
178 {
179 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.NumberOfItems32);
180 if (c != null)
181 {
182 if (incrementValue == 1)
183 c.Increment();
184 else
185 {
186 if (incrementValue == -1)
187 c.Decrement();
188 else
189 c.IncrementBy(incrementValue);
190 }
191 }
192 }
193
194 public void RateCounter(string category, string counterName, bool useInstance, int incrementValue)
195 {
196 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.RateOfCountsPerSecond32);
197 if (c != null)
198 {
199 if (incrementValue == 1)
200 c.Increment();
201 else
202 {
203 if (incrementValue == -1)
204 c.Decrement();
205 else
206 c.IncrementBy(incrementValue);
207 }
208 }
209 }
210
211 public void AvarageCounter(string category, string counterName, bool useInstance, long incrementValue)
212 {
213 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.AverageTimer32);
214 if (c != null)
215 {
216 PerformanceCounter cBase = GetCounter(category, counterName + "Base", useInstance, PerformanceCounterType.AverageTimer32);
217 c.IncrementBy(incrementValue);
218 cBase.Increment();
219 }
220 }
221
222 public void RemoveCurrentCounterInstance(string category, string counterName)
223 {
224 cacheLock.EnterReadLock();
225 try
226 {
227 if (categoryDict.ContainsKey(category) && categoryDict[category].ContainsKey(counterName))
228 {
229 if (PerformanceCounterCategory.CounterExists(counterName, category) && PerformanceCounterCategory.InstanceExists(AppDomain.CurrentDomain.FriendlyName, category))
230 {
231 PerformanceCounter c = categoryDict[category][counterName];
232 c.InstanceName = AppDomain.CurrentDomain.FriendlyName;
233 c.RemoveInstance();
234 }
235
236 }
237 }
238 finally
239 {
240 cacheLock.ExitReadLock();
241 }
242 }
243
244 public void SetNumberCounterValue(string category, string counterName, bool useInstance, int newValue)
245 {
246 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.NumberOfItems32);
247 if (c != null)
248 {
249 if (useInstance)
250 c.InstanceName = AppDomain.CurrentDomain.FriendlyName;
251 c.RawValue = newValue;
252 }
253 }
254 public void SetAvarageCounterValue(string category, string counterName, bool useInstance, long newValue)
255 {
256 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.AverageTimer32);
257 if (c != null)
258 {
259 PerformanceCounter cBase = GetCounter(category, counterName + "Base", useInstance, PerformanceCounterType.AverageTimer32);
260 if (useInstance)
261 c.InstanceName = AppDomain.CurrentDomain.FriendlyName;
262 c.RawValue = newValue;
263 if (newValue == 0)
264 c.RawValue = 0;
265 }
266 }
267 public void SetRateCounterValue(string category, string counterName, bool useInstance, int newValue)
268 {
269 PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.RateOfCountsPerSecond32);
270 if (c != null)
271 {
272 if (useInstance)
273 c.InstanceName = AppDomain.CurrentDomain.FriendlyName;
274 c.RawValue = newValue;
275 }
276 }
Deployment
Beim Deployment sollte man die Empfehlung von MS usw. berücksichtigen und bei der Installation alle Counter anlegen. Counter zu nutzen ist nicht sehr "teuer", allerdings ist es sehr aufwendig und langsam, wenn Counter angelegt werden. Zu mal immer alle Counter inklusive Category gelöscht wird.
Der einfachste Weg bei der Installation ist es eine Installer-Klasse zu erstellen, die alles Counter der Anwendung anlegt. hierfür ist ein bisschen Coding notwendig und anschließend einfach "installutil" aufrufen.
Eingestellt von
Jan Zieschang
um
07:39
1 Kommentare
Freitag, Juli 11, 2008
ASP.NET MVC Authorization (EntLib Rules)
Das letzte Wochenende habe ich mich mal wieder mit ASP.NET MVC beschäftigt, diesmal schon das 2. Wochenende mit der Autorisierung von Benutzern. Ich glaube, die Variante über den Enterprise Library Rules Provider ist der beste Weg.
Hier mal kurz die verschiedenen Möglichkeiten
- Enterprise Library Rules Provider - patterns & practices – Enterprise Library - Home
- eigener Controller - http://geekswithblogs.net/AzamSharp/archive/2008/02/24/119946.aspx
- Attribute - http://www.coderjournal.com/2008/03/securing-mvc-controller-actions/
- RouteHandler - http://blogs.msdn.com/mikeormond/archive/2008/06/21/asp-net-routing-and-authorization.aspx
- ActionFilter - http://blog.wekeroad.com/blog/aspnet-mvc-securing-your-controller-actions/
Also man hat sehr viele Möglichkeiten und wer sich mal durch die Links durchgeklickt hat, der wird auch mitbekommen haben, dass es sehr viele Diskussionen über den richtigen Weg gibt. Den Ausschlag für die Enterprise Library bei mir hat den Einsatz sowohl in Services, Web-Apss und WinForms mit externer Konfiguration gegeben. Man kann auch einige andere der oben aufgeführten Konzepte damit verbinden.
Aus meiner Sicht ist es schon sehr Vorteilhaft, wenn man ein Konzept einsetzt, dass über den Applikationstyp hinweg eingesetzt werden kann. Zum anderen bietet die Enterprise Library durch das Konfigurationstool eine einfache grafische Möglichkeit der Konfiguration, so dass Administratoren nicht unbedingt in die Tiefen eingeführt werden müssen. Aber bestimmt für Administratoren, die auf Sicherheit sehr viel Wert legen ist die Möglichkeit den AzMan einzusetzen. Hierbei handelt es sich um eine Konfiguration die im Active Directory abgelegt werden kann. Der Rules-Provider kann so verwendet werden, dass Geschäftsvorfälle als Regeln dienen. Es gibt noch eine Reihe weiterer netter Vorteile, also durchaus mal nachlesen.
Nun genug zu den Vorteilen, hier noch ein Verwendungsbeispiel:
1 <securityConfiguration defaultAuthorizationInstance="" defaultSecurityCacheInstance="">
2 <authorizationProviders>
3 <add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
4 name="ProjectRuleProvider">
5 <rules>
8 <add expression="R:Administrators OR R:Chef"
9 name="CreateProject" />
12 <add expression="R:Administrators OR R:Chef"
13 name="DeleteProject" />
16 <add expression="R:Administrators OR R:Chef"
17 name="EditProject" />
18 </rules>
19 </add>
20 </authorizationProviders>
21 </securityConfiguration>
Wie zu sehen ist, sind die einzelnen Regeln nur eine Zeile lang. Aber keine Angst, die Syntax ist einfach und es gibt zu dem das Konfigurationstool in dem sich noch weitere Sachen einfach zusammen klicken und testen lassen. Zur Konfiguration gehört eine solche Abfrage (die Zeilennummer sind nicht von oben):
26 IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider("ProjectRuleProvider");
27 return auth.Authorize(principal, "EditProject");
Bei Prinzipal handelt es sich um ein IPrinzipal-Objekt, dass zum Windows Nutzer oder zum Web-Nutzer gehört.
An dem Artikel habe ich jetzt eine Woche "gedoktort", dadurch ist er nicht besser geworden. :( MVC macht immer noch sehr viel Spass, aber nun muss ich auch mal an die Dokumentation ran, damit auch mal ein anderer das Zeug pflegen kann. Testfälle formulieren fehlt auch noch. :(
Eingestellt von
Jan Zieschang
um
20:36
0
Kommentare
Sonntag, Juni 29, 2008
Der Juni Monat
Ist nun schon eine Weile her, dass ich rein privates geschrieben habe. Daher nun mal ein kleiner Rückblick auf den Juni.
Der Juni ist immer ein Familienfeiermonat, meine Schwägerin hatte Geburtstag, ich hatte Anfang des Monats Geburtstag und schließlich auch noch mein Neffe. (übrigens, ähnlich war auch der Mai) Um nicht zu viel zu feiern, haben wir wenigstens 2 Geburtstage zusammen gelegt (1Tag vor meinem eigentlichen Geburtstag gefeiert). Es war aber schon eine ganze Menge zu tun, Salate, Fleisch einkaufen und noch bisschen kochen. Das Wetter war richtig Klasse und sehr warm, so hat es bei meinem Bruder im Garten richtig Spass gemacht. Meinen Geburtstag habe ich anschließend mit meinen besten Freunden in Berlin verbracht. Wir (inkl. 2 kleinen Kindern) haben schön Kaffee gegessen und anschließend ging es noch etwas durch die Stadt und anschließend zum grillen. War angenehm mit den 4 den Geburtstag zu verbringen.
Im Juni war dieses Jahr außerdem noch ein 4 tägiges Firmenevent. Um alle aus der Arbeit herauszureißen ging es etwa 150km Richtung Norden in den Robinson Club. In den 4 Tagen habe ich massig gegessen, es ist unglaublich, was in den Bauch alles so rein geht. Das nette an dem Event war, dass auch die Familien mit-/nachkommen durften, bei mir gab es niemanden, aber war interessant auch mal die Kinder der Kollegen zu sehen. Insgesamt ein schönes Event, das mit einem Sportlichen und Erholsamen Sonntag echt schön war. Anschließend hatte ich auch noch 3 Tages Muskelkater.
Den restlichen Monat habe ich nur mit Arbeit verbracht, fast nur. Ich bin zur Zeit mal wieder auf Dienstreisen und treibe mich in Deutschland rum. Ein Tag war noch Kirschernte bei meinen Bruder, natürlich nicht nur ernten sondern auch entspannen im Garten.
Mit einigen Kollegen wollten wir schon seit Anfang Mai endlich mal wieder Volleyball spielen. Aber wie die Welt so spielt, wir haben es einfach nicht hinbekommen. Aber der nächste Anlauf folgt demnächst.
Ansonsten ist bei mir aber nix los. Viele Freunde habe ich schon lange nicht mehr gesehen und ....
Nun noch schön auf das Deutschland-Spiel heute Einstimmen, die Fan-Meile ist wohl schon geschlossen und ich muss morgen gegen 5:00 aufstehen. Wir werden endlich mal wieder Europameister!
UPDATE: Leider war es nix mit dem Titel, aber wenigstens war das Fußballspiel ansehnlich. Spanien war im ganzen Spiel besser, zumindest mit den klar besseren Chancen. Gratulation! Nun ins Bett!
Eingestellt von
Jan Zieschang
um
19:41
0
Kommentare
Tags: privates
Sonntag, Juni 22, 2008
Kämpfen mit ASP.NET MVC
Ich habe mir dieses Wochenende mal wieder etwas Zeit für ein Projekt genommen, in dem das ASP.NET MVC-Framework zum Einsatz kommt. Das Arbeiten mit dem MVC-Framework macht mir richtig Spass. Aber dennoch gibt es einige Hacken, die einem den nerv rauben.
MVC Routing Trouble
Allgemein ist es wichtig, dass Routen nach der Reihenfolge des hinzufügen ausgewertet werden. Meistens sollte dass auch mit der Lesereihenfolge in der Global.asax übereinstimmen.
Meine erste Baustelle war das Routing bzw. die Übergaben von Parametern. Mir ist noch nicht klar, warum die Standardwerte in der Global.asax nicht weitergegeben werden. Meine Nullable-Parameters haben erhalten nicht den Wert. Für das Problem habe ich 2 mögliche Lösungsszenarien, zum einen kann man die Parameter nicht Nullable machen oder innerhalb der Methode ggf. den Standardwert setzen.
Bei einer meiner Routen wurden einer der 1. Parameter nur ab und zu gesetzt. Zur besseren Darstellung mal ein Beispiel:
Die Route:
new Route("Projects/Results/{client}/{customerName}/{projectName}/{page}/{pageSize}/{order}", new MvcRouteHandler()) { Defaults = new RouteValueDictionary(new { controller = "Projects", action = "Results", client = ClientEnum.SDC, customerName = "", projectName = "", page = 1, pageSize = 20, order = "Default" }), }
Signatur:
public void List(ClientEnum client, long page, long pageSize, string order) { this.Results(client, null, null, page, pageSize, order); }
Die Url:
http://localhost/Projects/search/customerPart/myProjectPart
In meinen Routen soll eigentlich die nicht mehr die Default.aspx aufgerufen werden, hierfür habe ich noch nicht die Lösung gefunden. Das Verhalten muss ich mir noch mal zu Gemüte führen und die Videos dazu anschauen, Vielleicht schon morgen im Zug.
SQL Paging Trouble
In der Anwendung greife ich auf einen Sql Server oder Sql Server Express mittels Paging zu, leider ist es kompliziert eine ordentliche Abfrage dafür zu erstellen. Normalerweise soll man für Paging-Abfragen RowNumber oder Rank benutzen, alternativ wird oft über Temp-Tables das Select erstellt. Allerdings ist das mit dem Sql Express nicht möglich, in dem Fall ist ein anderer Weg notwendig. Ich bin auf eine recht einfache Lösung im Internet gestoßen, dabei wird Top verwendet um die Ergebnismengen zu reduzieren. Das Grundprinzip für die Abfrae verwendet TOP mit unter Queries und könnte so aussehen:
SELECT top(ANZAHL) * FROM ( SELECT top(OFFSET + ANZAHL) * FROM MyTable ORDER BY xyz ASC ) as maxLimit ORDER BY xyz DESC
SETUP
Wer das MVC unter IIS6 benutzen will, sollte mal in die Blog-Einträge How to enable pretty urls with Asp.Net MVC and IIS6 oder Using ASP.NET MVC on IIS 6 without the .MVC Extension schauen. Besser kann man das nicht mehr beschreiben. Bei beiden Techniken wird Url-Rewriting eingesetzt. Ich würde aber den IIS7 empfehlen, da sind solche Umwege nicht mehr notwendig.
Eingestellt von
Jan Zieschang
um
19:27
0
Kommentare