Tuesday, March 29, 2011

The Dreyfus Model of Skills Acquisition (skill levels/taxonomy)

This is a copy of a posting originally found at http://blog.bruceabernethy.com/post/The-Dreyfus-Model-of-Skills-Acquisition.aspx however since that original posting/entire blog seems to have disappeared and as I actively use/find the taxonomy defined in this specific blog posting great I am reposting it here. All credits go to Bruce Abernethy.

UPDATE: It seems that Bruce Abernethy's blog is back up again, with a new nice design. The link is http://blog.bruceabernethy.com/myblog/2007/08/the-dreyfus-model-of-skills-acquisition/ (thank you for notifying me David). I will leave the posting here due to the few comments it has inspired, but recommend anyone to go to the original authors blog posting.

Regards
Kenneth Thorman

OK, this post will be a little “heady” for a Saturday morning but I want to reference this topic for some other work I am going to do this fall. I am planning to do some non-trivial work to get some resources and links online to help kids get into doing projects and learning about things like physics, space science, and robotics/electronics – things if you know me, you know I’ve been into for a long time. The problem with the way kids learn about these topics nowadays is that it is mostly abstract, in theories, reading, or just “on paper.” To really learn more than trivia and facts about these topics you really need to “do” things with the science, not just learn things “about” them.

There are several articles or models from people that really affect the way I am going to approach things, and have impacted my thinking about the approach to learning things. I’ll hit each of them separately and then pull them all together later as kind of an approach for what I am going to try. None of these articles or their ideas should really come as a surprise to anyone – they make sense when you read them. But the authors do a great job of describing things in a depth and detail that I never could.

The first article and model is the Dreyfus Model – which is based originally on a report by Hubert Dreyfus and Stuart Dreyfus in the early 80s called “A Five-Stage Model of the Mental Activities Involved in Directed Skill Acquisition.” I’ll try to link to the study itself which is in a PDF file (scanned in mirror 783k) – don’t read it yet, just follow along here for a minute.

This study was prepared initially for the Air Force Office of Scientific Research for the training of pilots, but its model and purpose has been used effectively for training everyone from pilots, to nurses, to chess players, foreign language learners, and even computer programmers (Google “Dreyfus Model” http://www.google.com/search?q=dreyfus+model and will see lots of different results of people using it (and some people arguing against it)). I like it, so I am going to use it.

To keep this to as few words as possible, Dreyfus identifies five to seven stages of learning a new skill or domain:

  • Novice,
  • Advanced Beginner,
  • Competent,
  • Proficient,
  • Expert, and
  • Master.
I don’t know about you but I find that many people use terms like “Competent” and “Expert” in describing their skills but really have no objective model for putting them in one category or another. Some people move themselves from not knowing anything about a particular skill up to “Competent” just by reading a book about the topic. Others call themselves an “Expert” after completing one project using a particular skill or technology. I am reminded of an episode of “Monk” where the detective Adrian Monk is going on a boat and someone asks him if he can swim. He says he knows how to swim, and even produces a card from his wallet certifying him as a swimmer (from a correspondence course), but also admits he has never actually been in the water to try out his skills but thinks he’ll do fine. Some people are that way with technology and other domains where they have studied it in books and on the Internet but have never really “done” real-world things to use what they have learned. You learn by doing things, you don’t (can’t) really learn before you do something.

What this model does is two important things: (1) helps better define what these stages of learning mean and (2) explains a workable model for moving people from one stage to the next.

Briefly, the stages:


Novice

A novice is all about following rules – specific rules, without context or modification. You don’t need to “think” you just need to “do”. A rule is absolute, and must never be violated. The main thing to do here is to get experience following directions and doing the new skill. You can follow the instructions on a box of cake mix and hopefully produce a decent cake. All you are responsible for is following directions.
“To improve, the novice needs monitoring, either by self-observation or instructional feedback, so as to bring his behavior more and more completely into conformity with the rule.”

Advanced Beginner

Still rules based, but rules start to have situational conditions. In one situation you use one rule, in other situations you use another. The advanced beginner needs to be able to identify the limited need to selectively apply different rules. So if you want a chocolate cake, follow the chocolate rule(s), if you want a vanilla cake, follow the other rule(s). If you are over 5,000ft of altitude you will need to alter the amount of some ingredients. This is still a recipe, but has a few decision points. Again, follow the different “branches” of instructions and you should be fine. It is easy to see how this could collapse into a large Novice category, but it is a step before the much larger step to Competence.

Competent

You realize that your skill or domain is more complex than a series of rules and branches. You start to see patterns and principles (or aspects) rather than a discrete set of rules – rules become “rules of thumb”. You are lead more by your experience and active decision-making than by strictly following rules. What is developed now are guidelines that help direct competent individuals at a higher level. You now are accountable for your decisions as you are not following the strict rules and context of the previous stages. You’ve made a lot of cakes and have a number of recipes. When asked to make a cake of a different type you pull from experience the best way to put a new cake together. If the new cake doesn’t work out, you are responsible. This is the critical tipping point for most people when learning a new skill – and why most people never really become “competent” in most things they learn. Here you either need to decide to just “follow the rules” or spend the time to get fully involved with and take responsibility.
“Competence comes only after considerable experience actually coping with real situations …”

Proficient

At this point your understanding of your skill or domain has become more of an instinct or intuition. You will do and try things because it just seems like the right thing to do (and you will most often be right). Instead of a discrete set of different parts you can perceive a complete system. A large amount of real-world experience will show you that there are often multiple competing solutions to a specific problem and you have a “gut feeling” about which is correct. “Calculation and rational analysis seem to disappear”. Will quickly know “what” needs to be done and then formulate how to do it. Proficiency is developed by exposure to a “wide variety of typical whole situations.”

Expert

At this point you are not solving problems or making conscious decisions about things, you just “do” and it works. “Optimal performance becomes second nature.” People may ask you why you decided to do things “that way” and you may not know how to explain to them the 10 steps necessary to get from “A” to “B” because to you it was really just one step. Forcing an expert to detail the steps necessary before proceeding will often cause them to fail or second-guess. Here you think of grandma getting up at 6:00am and making biscuits from scratch for many, many years. She doesn’t measure, time, or probably even think about baking – she just does it, and it works. Very few people will attain this level in a particular skill or domain. Some estimates say 10-15 years in a particular area is required.
An Expert has experience that “is so vast that normally each specific situation immediately dictates an intuitively appropriate action.”

Master

Mastery is mostly about style. A Master of something is really just an “Expert on a roll.” Sometimes you may have witnessed someone or spent time with someone who is so good at something, and gets so caught up in doing it, that you can’t help but feel that you are watching a genius at work. I’d also say a Master is an Expert who can look back and put themselves in a Novice’s shoes and create the rules, and do the monitoring/mentoring necessary to help them move forward. If you have met a Master you remember them – by name – they are rare and you would do well to spend as much time with them as possible. An Expert basketball player could be excellent at execution and without formal thought just picture the ball going through the hoop (and it does). But Michael Jordan could do it with such style, grace and physics-defying ease that you just had to stop everything and watch him when he was “in the groove.”
A Master “is capable of experiencing moments of intense absorption in his work, during which his performance transcends even its usual high level.”

The Point

If you’ve read this far, thanks, and I’ll get to the point (1,000+ words later) – I believe that too many people today are learning just enough to be considered an “Advanced Beginner” in the vast majority of topics. Painfully this is increasingly true in science, math and technology. If you know enough to “pass the test” then that is all you need to know. The No Child Left Behind law was designed to keep people accountable for learning. But instead of having students be able to become Competent or even Proficient in a handful of skills, we have instead created a system where we have students stuck at “Advanced Beginner” in many more subjects – and perhaps unable to move forward. We are teaching kids that it is enough to know “about” things, but not actually “do” things.
So what can we do about it? We need to catalog and create a list of resources that will help kids get from Novice to Competent in science, math, and technology - things that will get them active in doing projects and making the connections necessary to move ahead. A lofty goal, but attainable. Many people are seeing similar voids and doing things about it. Linking and teaming with them will be key in our success.

More on this to come …..
Bruce

p.s. I need a good label for "Level 0" - before Novice - before you've ever really started learning about a particular topic.  "Ignorant" is cold, as is "Empty" - "Unaware" sounds judgmental.  If you haven't heard of Newton's Laws of Motion it most likely isn't your fault, but you aren't quite a "Novice" yet in its study.  Something positive like "ready" or "waiting"  or "willing" - ideas are welcome.

Wednesday, March 23, 2011

Mark Seeman: Dependency Injection in .NET

I started reading Mark Seeman's book "Dependency Injection in .NET" yesterday evening. So far I have been through the first 4 chapters, and I find the mix of culinary hint and anecdotes a fresh and welcome take on writing factual development / programming books.

From what I have read so far I can highly recommend this book from a technical perspective.

For anyone interested in designing decoupled software and especially .NET developers this is a MUST read. Many of the concepts and techniques described in the book are relevant  for most other programming languages as well.




Monday, March 21, 2011

ASP.NET MVC 3 Dependency Injection using Windsor Castle, Singleton Lifestyle and object not set to an instance

Dependency Injection and Inversion of Control is an increasingly common and popular design principle in ASP.NET MVC.

However for the uninitiated (and even for those how have worked with it for some time) you can run into unexpected errors, especially when mixing Lifestyles for different Components on larger projects where you have multiple container installers/initializers.

I will here present a very obvious case that nevertheless had me and another developer spending a few hours trying to figure out what was wrong. This bug presented here are especially difficult to track down when you are doing frequent builds on a development machine and that build process causes the IIS application pool(s) to recycle, effectively resetting the IoC container.

I will be using Castle Windsor as the IoC (Inversion of Control) container in this posting.

The zipped solution can be downloaded here IocLifestyles.zip

First of all we will need to start with a new standard empty ASP.MVC NET 3.0 site/project and add a reference to Castle.Windsor. This reference can be added using NuGet or by downloading the source or binary libraries at the 
Castle Windsor website.

Secondly we need to tell ASP.NET MVC that we do not want to use the DefaultControllerFactory to create controller instances but that we want to use our own which in turn uses Windsor to provide the dependencies the various controllers need.

I do this in the Global.asax file by adding the following lines in the Application_Start method.


// Using WindsorControllerFactory rather then DependencyResolver
// http://bradwilson.typepad.com/blog/2010/07/service-location-pt1-introduction.html (read comments)
// http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html (read comments)
// http://bradwilson.typepad.com/blog/2010/10/service-location-pt10-controller-activator.html (read comments)
// http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html
// http://kozmic.pl/2010/08/19/must-windsor-track-my-components/
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(applicationWideWindsorContainer));

// Initialize / install components in container
applicationWideWindsorContainer.Install(new WindsorInstaller());
As well as the the field

WindsorContainer applicationWideWindsorContainer = new WindsorContainer();
This leads to our Global.asax files looking like this

using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;

namespace IocLifestyles
{
 // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
 // visit http://go.microsoft.com/?LinkId=9394801

 public class MvcApplication : System.Web.HttpApplication
 {
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
   filters.Add(new HandleErrorAttribute());
  }

  public static void RegisterRoutes(RouteCollection routes)
  {
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

   routes.MapRoute(
     "Default", // Route name
     "{controller}/{action}/{id}", // URL with parameters
     new { controller = "Default", action = "Index", id = UrlParameter.Optional } // Parameter defaults
   );

  }

  WindsorContainer applicationWideWindsorContainer = new WindsorContainer();

  protected void Application_Start()
  {
   AreaRegistration.RegisterAllAreas();

   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes);

   // Using WindsorControllerFactory rather then DependencyResolver
   // http://bradwilson.typepad.com/blog/2010/07/service-location-pt1-introduction.html (read comments)
   // http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html (read comments)
   // http://bradwilson.typepad.com/blog/2010/10/service-location-pt10-controller-activator.html (read comments)
   // http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html
   // http://kozmic.pl/2010/08/19/must-windsor-track-my-components/
   ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(applicationWideWindsorContainer));

   // Initialize / install components in container
   applicationWideWindsorContainer.Install(new WindsorInstaller());
  }
 }
}

We now need to look closer at 2 classes, namely the WindsorControllerFactory and the WindsorInstaller.

The responsibility of the WindsorControllerFactory is to provide all the objects to the controller which it depends on to perform it's logic. This is passed in to the controllers constructor. This is done using Constructor Injection (you can see a lot of good tips, thoughts and recommendations at Mark Seeman's blog).

using System;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;

namespace IocLifestyles
{
 public class WindsorControllerFactory : DefaultControllerFactory
 {
  private readonly IWindsorContainer windsorContainer;

  public WindsorControllerFactory(IWindsorContainer windsorContainer)
  {
   this.windsorContainer = windsorContainer;
  }

  protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  {
   return windsorContainer.Resolve(controllerType) as IController;
  }

  public override void ReleaseController(IController controller)
  {
   var disposableController = controller as IDisposable;
   if (disposableController != null)
   {
    disposableController.Dispose();
   }

   windsorContainer.Release(controller);
  }
 }
}
Now we need to register the classes which we are going to use through out our application with the IoC container and we do this by implementing the IWindsorInstaller interface.

Please note the Lifestyles for the different components, since this is the key to the bug I am going to illustrate.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>());
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

Looking closer at the 2 classes that we have registered in the WindsorInstaller: SomeRepository and SessionValidator.

namespace IocLifestyles
{
 public interface ISomeRepository
 {
  SessionToken GetSessionToken();
 }

 public class SomeRepository : ISomeRepository
 {
  private readonly ISessionValidator sessionValidator;

  public SomeRepository(ISessionValidator sessionValidator)
  {
   this.sessionValidator = sessionValidator;
  }

  public SessionToken GetSessionToken()
  {
   return sessionValidator.ValidateSession();
  }
 }
}
using System.Net;
using System.Web;

namespace IocLifestyles
{
 public interface ISessionValidator
 {
  SessionToken ValidateSession();
 }
 public class SessionValidator : ISessionValidator
 {
  private readonly HttpContextBase httpContextBase;

  public SessionValidator(HttpContextBase httpContextBase)
  {
   this.httpContextBase = httpContextBase;
  }

  public SessionToken ValidateSession()
  {
   // Do some validation here
   var sessionToken = new SessionToken
             {
              IpAddress = IPAddress.Parse(httpContextBase.Request.UserHostAddress),
              IsValid = true
             };

   return sessionToken;
  }
 }
}
The final 2 pieces needed to actually see something in the browser is the DefaultController
using System.Web.Mvc;

namespace IocLifestyles.Controllers
{
 public class DefaultController : Controller
 {
  private readonly ISomeRepository someRepository;

  // Constructor Injection
  public DefaultController(ISomeRepository someRepository)
  {
   this.someRepository = someRepository;
  }

  public ActionResult Index()
  {
   ViewData.Model = someRepository.GetSessionToken();
   return View();
  }
 }
}

and the Views/Default/Index.cshtml view.

@model IocLifestyles.SessionToken
@{
 ViewBag.Title = "Index";
}
<h2>
 SessionToken IpAddress: @Model.IpAddress.ToString()</h2>

This is a rather contrived example, but please bear with me for the sake of demonstration purposes.

What is interesting however is what happens when we run the application the first time and contrast this to what happens when we run it a second time without rebuilding the code.

First time:


Second and subsequent times:



Playing around with this you will notice that you can display the page one time after a build, this is giving us an indication of what is wrong.


Below you can see the full stack trace with all details
Server Error in '/' Application.
Object reference not set to an instance of an object.
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.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 20:   {
Line 21:    // Do some validation here
Line 22:    var sessionToken = new SessionToken
Line 23:              {
Line 24:               IpAddress = IPAddress.Parse(httpContextBase.Request.UserHostAddress),


Source File: D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SessionValidator.cs    Line: 22

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
   Microsoft.VisualStudio.WebHost.Connection.get_RemoteIP() +0
   Microsoft.VisualStudio.WebHost.Request.GetRemoteAddress() +65
   System.Web.HttpRequestWrapper.get_UserHostAddress() +22
   IocLifestyles.SessionValidator.ValidateSession() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SessionValidator.cs:22
   IocLifestyles.SomeRepository.GetSessionToken() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SomeRepository.cs:19
   IocLifestyles.Controllers.DefaultController.Index() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\Controllers\DefaultController.cs:17
   lambda_method(Closure , ControllerBase , Object[] ) +96
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +55
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +263
   System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +191
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
   System.Web.Mvc.Controller.ExecuteCore() +116
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8862285
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.208

The reason this is failing is the mixing of Lifestyles in the WindsorInstaller. Lets bring up that particular code again.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>());
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

The default lifestyle is Singleton. Omitting the lifestyle on ISomeRepository will register it as a Lifestyle.Singleton. SomeRepository will be instantiated one time by Windsor and then cached internally for future use. This means that even though all the other registered Components are Lifestyle.PerWebRequest, ISomeRepository will not be able to benefit from this.

There are no warnings that helps you if you mix Lifestyles in your installers, and especially in larger projects, this can be a challenge when you start tweaking for memory/performance reasons.
You need to know how all the dependencies work, and how they are used, to be able tweak Lifestyles for components. If you do not have this knowledge the risk is very high that you will introduce bugs. My suggestion especially if you are new to ASP.NET MVC leave Lifestyles to Lifestyle.PerWebRequest for all components, unless it is very obvious that this is a real singleton component. Only start tweaking Lifestyles if performance or memory consumption becomes a problem.

Changing the installer to the following solves the problem.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>().LifeStyle.PerWebRequest);
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

Monday, March 14, 2011

Is throw null and throw new NullReferenceException() the same?

A few times I have seen the use of 
throw null;
where a more verbosely inclined programmer would have written 
throw new NullReferenceException();
So I set out to find out if these 2 uses indeed are equivalent.
Starting out with the code for our class, the matching generated MSIL and finally the stack trace.
using System;
namespace NullRefernceException
{
 public class Class1
 {
  public void DoSomething()
  {
   throw null;
  }
 }
}
.method public hidebysig instance void  DoSomething() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  ldnull
  IL_0001:  throw
} // end of method Class1::DoSomething
System.NullReferenceException: Object reference not set to an instance of an object.
   at NullRefernceException.Class1.DoSomething() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1.cs:line 8
   at NullRefernceException.Class1Tests.DoSomething_TestDriveNullReferenceException_ExceptionThrown() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1Tests.cs:line 15

And now for the version of the code that is using throw new NullReferenceException

using System;
namespace NullRefernceException
{
 public class Class1
 {
  public void DoSomething()
  {
   throw new NullReferenceException();
  }
 }
}
.method public hidebysig instance void  DoSomething() cil managed
{
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  newobj     instance void [mscorlib]System.NullReferenceException::.ctor()
  IL_0005:  throw
} // end of method Class1::DoSomething
System.NullReferenceException: Object reference not set to an instance of an object.
   at NullRefernceException.Class1.DoSomething() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1.cs:line 8
   at NullRefernceException.Class1Tests.DoSomething_TestDriveNullReferenceException_ExceptionThrown() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1Tests.cs:line 15


And the test used to drive

using System;
using NUnit.Framework;

namespace NullRefernceException
{
 [TestFixture]
 public class Class1Tests
 {
  [Test]
  public void DoSomething_TestDriveNullReferenceException_ExceptionThrown()
  {
   var class1 = new Class1();
   try
   {
    class1.DoSomething();
   }
   catch (Exception exception)
   {
    Console.WriteLine(exception);
   }
  }
 }
}

So from a stacktrace point of view it does not look like there is a difference but in IL there is a difference.

After going through this exercise in code I flexed my Google Fu powers :) and found more information at this link on Stackoverflow - Why does C# allow you to 'throw null'?

Saturday, March 12, 2011

IIS administration using C# - multiple websites text search and replace in physicalpath

I recently found myself in a situation where I had several different web applications that where branches/tagged/deployed as a unit. When working with several different feature branches this leads to either having quite a few individual sites in IIS or updating the configurations of the existing IIS sites when switching to another branch. Since the setup and configuration of these sites was non-trivial, I ended up wondering if I could have one setup in IIS and then just bulk update the web applications physical path using a search and replace functionality.


Initially I tried vbs, but then I found this nice dll Microsoft.Web.Administration, which allows you to perform IIS administration from C#/.NET.


We have the following file system layout



Looking at the IIS administration tool we are currently pointing to branch1.





Running the program and bulk updating one or more site's physical paths.



Looking in the IIS administration again we see that the physical path of the site has been updated.



The source code below is pretty self explanatory. (Please note that I have kept the sources to the bare minimum to illustrate working with the Web.Administration API, rather than doing null checks, array length checks, try catches ...)


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Web.Administration;

namespace UpdateIisApplicationPaths
{
 public partial class Form1 : Form
 {
  private readonly ServerManager serverManager = new ServerManager();
  public Form1()
  {
   InitializeComponent();
  }

  private void Form1_Load(object sender, EventArgs e)
  {
   foreach (var site in serverManager.Sites)
   {
    websitesListBox.Items.Add(site.Name);
   }  
  }

  private void commitChangesButton_Click(object sender, EventArgs e)
  {
   Cursor.Current = Cursors.WaitCursor;
   foreach (var sitename in websitesListBox.SelectedItems)
   {
    var physicalPath = serverManager.Sites[(string) sitename].Applications[0].VirtualDirectories[0].PhysicalPath;
    physicalPath = physicalPath.Replace(oldPhysicalSitePathTextBox.Text, newPhysicalSitePathTextBox.Text);
    serverManager.Sites[(string) sitename].Applications[0].VirtualDirectories[0].PhysicalPath = physicalPath;
   }
   serverManager.CommitChanges();
   Cursor.Current = Cursors.Default;
  }

  private void websitesListBox_SelectedIndexChanged(object sender, EventArgs e)
  {
   if (websitesListBox.SelectedItems.Count > 0)
   {
    oldPhysicalSitePathTextBox.Text =
     serverManager.Sites[(string) websitesListBox.SelectedItems[0]].Applications[0].VirtualDirectories[0].PhysicalPath;
   }
  }
 }
}