Wednesday, 27 February 2008
Earthquake in London
At some point I felt like an earthquake, and I said that to my friend, who answered me: "we are in London, there cannot be earthquakes, it was just me shaking the table". Then he moved again his body, and I felt another shake.
Well, this morning news were full of reports about an earthquake in London, shouting things like "Biggest earthquake in London in 25 years", it seems of about 5.3 Richter, just before 1AM!!!!
So I felt a real earthquake, not just my friend shaking his bottom side :)
Tuesday, 26 February 2008
Remember the license, remember
Have you ever got any issue with the license of a command line tool?
Well, I've got one that caused me to loose half a day!
The tool I am using is PsExec, part of the Windows Sysinternals suite.
Wonderful suite, but when you use for the first time most of its tools, a dialog like this appears:
If you are working interactively, that's obviously not an issue, you read the license, you print it if you wish so, and then you freely decide if agreeing or not, but what if you are not in interactive mode? What if psExec is being used by some service, which is running using the Local System Account?
Yeah, probably after loosing half a day you will have an intuition, and you will log on as Local System (i.e. like i did here) to accept that license, but possibly you will not, and you will go on banging your head on why in earth that service is running perfectly in machine1, but stop to work somewhere in the middle in machine2.
Tuesday, 4 September 2007
AutoEventWireup is evil!
Summary
AutoEvenWireup is evil, especially if you need performance and scalability.
Setting it to true will add hundreds of function calls at runtime to the code which is running you Asp.Net page (probably thousands if there have many controls), function calls that could be safely avoided manually plugging the event handlers you need to deal with.
Investigating AutoEventWireup
A few years ago, I read in a Microsoft document that the AutoEventWireup attribute of the Asp.Net @ Page directive, although handy and probably even cherished by some, especially those from a VB background, is in truth only suitable for prototyping and only whenever performance and scalability are not an issue. Well, if you wonder when performance and scalability are not an issue, you should probably read on!
Let's imagine to have an ASP.Net project called Riolo.Investigation.Web, and to put inside a folder called AutoEventWireup an ASP.Net page called True.aspx, with the corresponding True.aspx.cs code behind file.
This is the ASP.NET page source code:
<%@ Page
Language = "C#"
AutoEventWireup = "true"
Inherits = "Riolo.Investigation.Web.AutoEventWireup.True"
ValidateRequest = "false"
EnableSessionState = "false"
CodeFile = "True.aspx.cs"
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>True</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE" />
<meta http-equiv="PRAGMA" content="NO-CACHE" />
<link href="Riolo.Investigation.Web.AutoEventWireup.css" type="text/css" rel="stylesheet" />
</head>
<body>
<% = _message %>
</body>
</html>
This is the c# code behind file source code:
using System.Web.UI;
namespace Riolo.Investigation.Web.AutoEventWireup
{
public partial class True : Page
{
protected string _message;
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
_message = string.Format
("SupportAutoEvents is {0}", base.SupportAutoEvents);
}
}
}
}
After compiling the ASP.Net project, after I get the True.aspx page from an ASP.Net enabled web server, I can see the following text on my browser:
SupportAutoEvents is True
When I take a look at the underlying HTML, I can see the following resulting source code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>True</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE" />
<meta http-equiv="PRAGMA" content="NO-CACHE" />
<link href="Riolo.Investigation.Web.AutoEventWireup.css" type="text/css" rel="stylesheet" />
</head>
<body>
SupportAutoEvents is True
</body>
</html>
What is happening?
What is happening is that setting the AutoEventWireup to true is telling the ASP.Net runtime engine to generate some delegates that enables us to use the methods with the following signatures to intercept the corresponding events of the ASP.Net page lifecycle:
- Page_PreInit
- Page_PreLoad
- Page_LoadComplete
- Page_PreRenderComplete
- Page_InitComplete
- Page_SaveStateComplete
- Page_Init
- Page_Load
- Page_DataBind
- Page_PreRender
- Page_Unload
- Page_Error
- Page_AbortTransaction
- OnTransactionAbort
- Page_CommitTransaction
- OnTransactionCommit
In the example before I used the Page_Load method to get the value of the SupportAutoEvent property and to put that in a nicely formatted string, which will be then printed inside the body of the resulting HTML.
Relying on the ASP.Net runtime to generate these delegates for us has a price, anyway, and this price is going to get quite expensive if our ASP.NET pages will become popular.
The price to pay
First of all, let's precise that this is an ASP.Net implementation issue, that is you get it on the platform targeted by my investigation (.Net 2.0), but some smarter future implementation could easily make it cheaper, pretty cheaper indeed. For the time being, anyway, the price is there to pay.
How high is this price, anyway? The key is an internal method of the abstract class System.Web.UI.TemplateControl called HookUpAutomaticHandlers().
There are various ways that are leading our pages and controls to HookUpAutomaticHandlers, the following is probably one of the more common:
System.Web.UI.TemplateControl.GetDelegateInformationWithNoAssert(IDictionary) : Void
System.Web.UI.TemplateControl.GetDelegateInformation(IDictionary) : Void
System.Web.UI.TemplateControl.HookUpAutomaticHandlers() : Void
System.Web.UI.Page.SetIntrinsics(HttpContext, Boolean) : Void
System.Web.UI.Page.SetIntrinsics(HttpContext) : Void
System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext) : Void
System.Web.UI.Page.ProcessRequest(HttpContext) : Void
ASP.autoeventwireup_true_aspx.ProcessRequest(HttpContext) : Void
If we take a look to HookUpAutomaticHandlers (thanks to Lutz Roeder's Reflector), we will notice that its code is executed only if the SupportAutoEvents is set to true:
internal void HookUpAutomaticHandlers()
{
if (this.SupportAutoEvents)
{
object obj2 = _eventListCache[base.GetType()];
IDictionary dictionary = null;
if (obj2 == null)
{
lock (_lockObject)
{
obj2 = _eventListCache[base.GetType()];
if (obj2 == null)
{
dictionary = new ListDictionary();
this.GetDelegateInformation(dictionary);
if (dictionary.Count == 0)
{
obj2 = _emptyEventSingleton;
}
else
{
obj2 = dictionary;
}
_eventListCache[base.GetType()] = obj2;
}
}
}
if (obj2 != _emptyEventSingleton)
{
dictionary = (IDictionary) obj2;
foreach (string text in dictionary.Keys)
{
EventMethodInfo info = (EventMethodInfo) dictionary[text];
bool flag = false;
MethodInfo methodInfo = info.MethodInfo;
Delegate delegate2 = base.Events[_eventObjects[text]];
if (delegate2 != null)
{
foreach (Delegate delegate3 in delegate2.GetInvocationList())
{
if (delegate3.Method.Equals(methodInfo))
{
flag = true;
break;
}
}
}
if (!flag)
{
IntPtr functionPointer = methodInfo.MethodHandle.GetFunctionPointer();
EventHandler handler = new CalliEventHandlerDelegateProxy(this, functionPointer, info.IsArgless).Handler;
base.Events.AddHandler(_eventObjects[text], handler);
}
}
}
}
}
That's it, setting AutoEventWireup to true will set SupportAutoEvents to true, and once HookUpAutomaticHandlers will be called, and it will be called for any page and all the controls in the page, will cause all of that code in red, using foreach, reflection, locks and especially calling GetDelegateInformation(IDictionary), which in turn will call GetDelegateInformationWithNoAssert(IDictionary dictionary). Using Reflector, let's take a look at that:
private void GetDelegateInformationWithNoAssert(IDictionary dictionary)
{
if (this is Page)
{
this.GetDelegateInformationFromMethod("Page_PreInit", dictionary);
this.GetDelegateInformationFromMethod("Page_PreLoad", dictionary);
this.GetDelegateInformationFromMethod("Page_LoadComplete", dictionary);
this.GetDelegateInformationFromMethod("Page_PreRenderComplete", dictionary);
this.GetDelegateInformationFromMethod("Page_InitComplete", dictionary);
this.GetDelegateInformationFromMethod("Page_SaveStateComplete", dictionary);
}
this.GetDelegateInformationFromMethod("Page_Init", dictionary);
this.GetDelegateInformationFromMethod("Page_Load", dictionary);
this.GetDelegateInformationFromMethod("Page_DataBind", dictionary);
this.GetDelegateInformationFromMethod("Page_PreRender", dictionary);
this.GetDelegateInformationFromMethod("Page_Unload", dictionary);
this.GetDelegateInformationFromMethod("Page_Error", dictionary);
if (!this.GetDelegateInformationFromMethod("Page_AbortTransaction", dictionary))
{
this.GetDelegateInformationFromMethod("OnTransactionAbort", dictionary);
}
if (!this.GetDelegateInformationFromMethod("Page_CommitTransaction", dictionary))
{
this.GetDelegateInformationFromMethod("OnTransactionCommit", dictionary);
}
}
As you can see, GetDelegateInformationFromMethod(..) is called a minimum 14 times from each page and a minimum of 8 time from each control in the page! GetDelegateInformationFromMethod(..) will then call System.Delegate.CreateDelegate(..) and the .Net trail will end when that will call the extern method BindToMethodInfo(..).
It is quite impressive that all of this is basically for nothing! If you think about it a few seconds, you will realize that you may save your web pages hundreds if not probably thousands of function calls just setting AutoEventWireup to false. We may then follow others strategies to handle events happening during the lifecycle of the Asp.Net pages and controls, but before introducing those, let's take a look at what happens when we set AutoEventWireup to false.
Setting AutoEventWireup to false
I created a new Asp.Net page in the AutoEventWireup folder, and I called that False.aspx, and then I created a new code behind c# file, and I called that False.aspx.cs, and then I copied inside them the code from True.aspx and from True.aspx.cs respectively. Togheter with AutoEventWireup I had to change also the values of the CodeFile and Inherits attributes of the @ Page directive.
If we compile the web site, and we ask False.aspx from an Asp.Net enabled web server, we will quickly notice that the code inside the Page_Load(..) method is not running anymore.
This is happening because at compile time the Asp.Net compiler is overriding the SupportAutoEvents property, which will now returns false, so the code inside HookUpAutomaticHandlers() is not running anymore, so no precooked delegates will be created for us at runtime.
You may confirm that going to the Temporary ASP.NET Files folder (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\ in my machine) and drilling down to the folder containing false.aspx.[x].compiled ([x] was ef11d7f0 in my case) file. If you open that file with a text editor, you will notice it is an xml file, and if you check the assembly attribute of the preserve element, you will read the name of the assembly where the Asp.Net page has been compiled in (in my case, it was App_Web_rzqguydd.dll).
You may choose to investigate that assembly with Reflector, but you may notice that there are a set of *.cs file starting with the same of the assembly. If you open these, if you will find one of them is containing a public class named autoeventwireup_false_aspx, which is where SupportAutoEvents get overridden and set to false.
Alternative Strategies
The alternative strategy is basically that of manually create the delegate and plug the event handler, as in the following version of False.aspx.cs:
using System.Web.UI;
namespace Riolo.Investigation.Web.AutoEventWireup
{
public partial class False : Page
{
protected string _message;
protected override void OnInit(System.EventArgs e)
{
base.OnInit(e);
this.Load += new System.EventHandler(Page_Load);
}
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
_message = string.Format
("SupportAutoEvents is {0}", base.SupportAutoEvents);
}
}
}
}
Instead of plugging the event handler inside the OnInit(..) method, you may plug it inside a constructor, but another alternative is that of getting rid of Page_Load(..) and using OnInit(..) directly.
Thursday, 30 August 2007
How to pass parameters set at runtime to the log4net configuration
We could in example put the following appender in our log4net configuration section:
<appender name="SystemAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\Logs\%property{LogFileName}.log" />
<appendToFile value="true" />
<maximumFileSize value="1000KB"/>
<maxSizeRollBackups value="2"/>
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %thread %logger - %message%newline"/>
</layout>
</appender>
Did you noticed the attributes of the file element? Togheter with the usual
value, we got also a type, set to log4net.Util.PatternString, and if you double check, you will notice also the value is a bit unusual: part of the string is a %property{LogFileName} substring.Now, that substring is telling to the log4net to look for a property called LogFileName in its ThreadContext. If you set that property before the call to XmlConfigurator.Configure, as in the following snippet, you will be able to programmatically set it at runtime:
log4net.ThreadContext.Properties["LogFileName"] = "MyApplication";
log4net.Config.XmlConfigurator.Configure();
This will set your log file to C:\Logs\MyApplication.log.
This approach can be useful in many scenarios, but probably not so efficient if you wish to multiplex the log entries to different files, because everytime you set the LogFileName property, you need to call again XmlConfigurator.Configure().
Thanks to Max Leifer to show us this technic :)
Monday, 13 August 2007
Installing a missing component on Microsoft SQL Server 2005 sp2
I thought it should be an easy exercise. I thought so.
First of all, I quickly discovered the service pack 2 had been installed in this machine, but quite irregurarly: that is, some components were on sp2, some others on sp2 pre-5th March, some other one on sp2 post-5th March (if you are not an insider, Bow Ward as a quite revealing explanation of the mess that was sp2).
Following an officemate's advice (cheers Alex!), I decided first to bring everythign at GDR2 (that is 9.00.3054), then I tried to add the missing components (once there, I decided to add also NS, even if I am going to stop it straight away!).
Here is where I discovered (or rediscovered? I am pretty familiar with this argument, but I can't remember to have met this issue before) that SKUUPGRADE is not the same than skuupgrade ..
That said, this is what I got to see when I finally get to choose the components to add:
Isn't that misleading? I mean, what I wish to achieve is to add some component not previously installed (by rule, if not otherwise required by security policies or other issues, I do ever install all the available components, and then disable the services I don't need). This interface clearly leading (me at last) to believe that the Database Services and the other components paired with the red x will be uninstalled, which will not happen. What this is trying to communicate is that the components I have installed on my machine are not the components on the install file, but if so, would be easier to just show that (i.e. showing Database Services as installed, but with the version number in braces).
Yep, all of this was a rant, but when people (well, me ..) have to waste 3 hours of their lives to add a component to an already installed software, there is definitively something smelling bad there ..
Monday, 7 May 2007
De Santis, Inter and Milan
He was barred from the approaching World Cup, and just after the end of the tournament he was banned until 2011. His career as a professional referee was completely ruined.
Monday 30th April, De Santis, a police constable, was guest of a TV program for a north Italian broadcaster, Antenna Tre Lombardia. During the program, he declared that he never talked on the phone with the former Juventus director Luciano Moggi, who was present, and the he also confessed that during his not so short career as a Serie A referee he received a lot of calls from former Inter president, the late Giacinto Facchetti, and former Milan “liaisons with referees” manager Luca Meani.
He also confessed to be an Inter supporter, and that he used to enjoy a very fine relationship with the late Facchetti, marred only from some occasional requests that “some time went also beyond the legal”.
Italian media basically skipped about this story, when they reported it they were mostly commenting about De Santis’ bad taste on talking about some already dead fellow.
Mainstream Italian media (apart a few lines http://qn.quotidiano.net/2007/05/04/9333-santis_sentito_moggi_facchetti.shtml) and English media basically ignored De Santis’ comments so far.
Friday, 13 April 2007
Improving build performances: assemblies on the GAC
Obviously, there is a time when you need a fast build, and there is a time when you need to be sure that all the assemblies your application is using are in the /bin folder, so I wrote 2 batch files to cache and uncache the assemblies listed in 2 text files (some example code at the end of the article).
I tested on my machine with a sizable web application project the effect of having or not having those assemblies on the GAC on the build time, and this are the rounded average results:
Solution
GAC 10"
No-GAC 27"
Web
GAC 5"
No-GAC 22"
That is, on my machine when I put the files on the GAC, when building I gain 17".
[Note: The web build is normally 5" faster than the Solution build because in the solution there are project not directly needed by the Web (In primis the tests, then some data migration and seeding stuff, some productivity measurament tool, and so on).]
Why it happens? My best answer is that having the Castle project assemblies in the GAC means that during the build these are not copied anymore in the various /bin folders.
I do advice you to try to test this in your machines as well, anyway, please read carefully and make sure you understand the next points before moving ahead:
- the build phase generate assemblies from the source code. Those assemblies are bytecode, not executable programs, and if not opportunely precompiled, they will be compiled at the startup of the .Net application. This means that after building, when you will refresh the web page, this will take exactly the same time to answer you as it was taking before putting the Castle Project assemblies on the GAC.
- I had to modify the web.config, because the assembly Castle.ActiveRecord has to be explicitly added this way.
- You may notice I also added Castle.Monorail.Framework and Castle.Monorail.Views.Brail. Unfortunately it seems IIS is requiring those two files before reading all the web.config, so I add to change the property Copy Local to true (so in the /bin folder of the web application project you still can find these two assemblies and their related files). This means that you need to slightly the web application project as well to get those latest needed changes.
- I didn't test the web with a web site project configuration, if you happen to use such, you will probably get an error due missing assemblies. I do not advice to use such project option for an unending list of reasons, but if you really wish to persist on your own way, you should solve that just making sure the appropriate assemblies are copied in the /bin folder of the web application. Manually (I mean with some pre o post build event) copying files is a bad practice, because it will worsen the performances of the build, so exercise with care.
- You may be tempted to modify the list of the assemblies to include in the GAC. Please exercise care when doing so, because you can only add strongly typed assemblies this way. In example Newtonsoft.Json is not in that list because it is not a strongly typed assembly.
- Microsoft doesn't recommed to put in the GAC the assemblies you are developing. That is, MyDomainModel.dll or MyInitialisation.dll have still to be keept outside the GAC. If in the future you stabilize one of those libraries, you may decide to sign it (to make it strongly typed) and that to add it to the GAC.
I tested all of this on this Monorail based web project, but its results will probably be more or less similar with normal ASP.NET projects.
Batch file to cache assemblies
pause
"C:\Program Files\Microsoft.NET\SDK\v2.0 64bit\Bin\gacutil" /f /il .\toCache.txt
pause
Batch file to uncache assemblies
pause
"C:\Program Files\Microsoft.NET\SDK\v2.0 64bit\Bin\gacutil" /f /ul .\toUncache.txt
pause
ToCache.txt (list of file to cache, note the relative path to the working directory of the batch file)
..\..\Resources\bin\anrControls.Markdown.NET.dll
..\..\Resources\bin\Boo.Lang.Compiler.dll
..\..\Resources\bin\Boo.Lang.dll
..\..\Resources\bin\Boo.Lang.Parser.dll
..\..\Resources\bin\Castle.ActiveRecord.dll
..\..\Resources\bin\Castle.Components.Binder.dll
..\..\Resources\bin\Castle.Components.Common.EmailSender.dll
..\..\Resources\bin\Castle.Components.Common.EmailSender.SmtpEmailSender.dll
..\..\Resources\bin\Castle.Core.dll
..\..\Resources\bin\Castle.DynamicProxy.dll
..\..\Resources\bin\Castle.Monorail.ActiveRecordSupport.dll
..\..\Resources\bin\Castle.Monorail.Framework.dll
..\..\Resources\bin\Castle.Monorail.Views.Brail.dll
..\..\Resources\bin\Castle.Services.Logging.Log4netIntegration.dll
..\..\Resources\bin\Iesi.Collections.dll
..\..\Resources\bin\log4net.dll
..\..\Resources\bin\NHibernate.dll
..\..\Resources\bin\NHibernate.Caches.SysCache.dll
..\..\Resources\bin\NHibernate.Generics.dll
..\..\Resources\bin\Nullables.dll
..\..\Resources\bin\Nullables.NHibernate.dll
Batch file to uncache assemblies
anrControls.Markdown.NET
Boo.Lang.Compiler
Boo.Lang
Boo.Lang.Parser
Castle.ActiveRecord
Castle.Components.Binder
Castle.Components.Common.EmailSender
Castle.Components.Common.EmailSender.SmtpEmailSender
Castle.Core
Castle.DynamicProxy
Castle.Monorail.ActiveRecordSupport
Castle.Monorail.Framework
Castle.Monorail.Views.Brail
Castle.Services.Logging.Log4netIntegration
Iesi.Collections
log4net
NHibernate
NHibernate.Caches.SysCache
NHibernate.Generics
Nullables
Nullables.NHibernate