Thursday, 22 May 2008

Diminuiscono gli articoli pubblicati su it.lavoro.informatica

Ecco un grafico che mostra il numero di articolo postati su it.lavoro.informatica dalla sua nascita, in serie per mese e per anno (12 mesi precedenti al mese incluso) diviso per il mese e per l'anno in cui si e' avuto un massimo di articoli:



La fonte dei dati e' Google Groups.

Dal grafico si deduce chiaramente che siamo in un periodo di decremento di articoli pubblicati.

Perche' questo avviene? E' un fenomeno passeggero, localizzato a questo gruppo, o stiamo assistendo all'inizio del tramonto di Usenet, come da tanti profetizzato?

Host headers on IIS with SSL

Do you wish to serve multiple web sites on the same IIS 6.0 server over SSL, using the same IP and the same 443 port? From the Windows 2003 server pack 1 you can.

Get a wildcard ssl certificate (i.e. with the common name *.yourwebsite.com), assign that wildcard ssl certificate to any website in your IIS, then ran the following commands for each website from C:\Inetpub\AdminScripts:

cscript.exe adsutil.vbs set /w3svc/<site identifier>/SecureBindings ":443:<host header>"

In example, if you wish to publish 3 websites called web, blog and mail identified in IIS as 1, 2 and 3, you have to run the following commands:

cscript.exe adsutil.vbs set /w3svc/1/SecureBindings ":443:web.yourwebsite.com"

cscript.exe adsutil.vbs set /w3svc/2/SecureBindings ":443:blog.yourwebsite.com"

cscript.exe adsutil.vbs set /w3svc/3/SecureBindings ":443:mail.yourwebsite.com"

More infos here.

Wednesday, 27 February 2008

Earthquake in London

This early morning, at around 1AM, I was laying down on the sofa talking with a friend, who was sitting on a small table in front of the sofa.
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

Today I learnt that it is possible to pass parameters set at runtime to the log4net configuration sections.
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

Today to set up a Team Foundation Server I noticed an instance of SQL Server 2005 was already installed on the machine. Unfortunately it was missing the Reporting Service component, which is required from TFS, so I decided to install it.
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 ..