Coding Kata on design patterns: Kata1, The Abstract Factory Pattern

 

This post is the first in a series dedicated to Coding Kata’s and design patterns.  

Because I’m not always able to remember all the patterns I decided to learn by practice.  

Every week I will try to create a Kata with a simple problem that has to be resolved with one of the Gov’s design patterns.  

Because I want to start smoothly we’ll start with one of the simplest pattern -> the Abstract Factory.

Kata1 ->

- A product has a property Name.  

- Because the Name is used as an identifier it can’t be changed.  

- We need to be able to construct 2 products with following names: Product1, Product2.

- Use the abstract factory pattern so that you’re able to create Products.

 

This is my solution for Kata1.

 

 

Sharepoint 2007 Certification Guide

Here under you can find two usefull ressources to prepare for the exam:

 

-       The Wrox book: Professional Sharepoint 2007 Development

 

-       The Blog of: Adam Roderick

 

By focusing primarily on these two resources I managed to pass the Sharepoint Certification with what could be considered a ‘high score’. 

Create a WCF service and client, using Msmq, programmatically

  download source code

Most of the WCF examples on the web uses the config file to setup the address, binding and contract of a WCF service. I dislike this way of configuring client and service in WCF because most of the time it leads to config files that are full of crab and that becomes unmanageable. I prefer to construct my WCF services programmatically. Therefore I’ve create a bunch of helper classes that contains most of the configuration settings that are applicable in a particular domain.

In this article I discuss one of these classes  I use to create local queues. With local I mean queues used by components making part of the same application. This class can be used as a factory to create the service (serviceHost) as well as the client part (Channel) for components communicating through Msmq.

This article provides a small tutorial on how to create a simple console app. I demonstrate how to create the client and service host without any configuration by using a helper factory class: WCFMsmqFactory

Prerequisite:

- This article assumes you’ve installed Msmq on your box.  If this isn’t the case install Msmq see->  here for Xp & Win server 2003 or here for Vista & Win 2008 & Seven.

- If you’re a vista user you need to register your namespace for by typing in the command (in administrator mode):
netsh http add urlacl url=http://+:8000/BackToOwner/gatewayservice/sms user=[your username]

1) Create a new console application project: ‘WCFMsmqFactory’ and add a reference to

  • System.ServiceModel
  • System.Messaging
  • System.Transactions

 

2) Create a the WcfMsmqFactory class by copying the source code here beneath:

   1:  public class WcfMsmqFactory<I, T> where T : I
   2:     {
   3:         private string _queueAddress;
   4:         public WcfMsmqFactory(string queueAddress)
   5:         {
   6:             _queueAddress = queueAddress; 
   7:   
   8:             if (!MessageQueue.Exists(queueAddress))
   9:                 MessageQueue.Create(queueAddress, true);
  10:         } 
  11:   
  12:         public ServiceHost CreateMsmqServiceHost(string metadataAddress, string namespaceName)
  13:         {
  14:             var sHost = new ServiceHost(typeof(T));
  15:             var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
  16:             binding.DeadLetterQueue = DeadLetterQueue.System;
  17:             binding.Namespace = namespaceName;
  18:             sHost.AddServiceEndpoint(typeof(I),
  19:                                            binding,
  20:                                            new Uri(String.Format(
  21:                                                        @"msmq.formatname:DIRECT=OS:{0}",
  22:                                                        _queueAddress)
  23:                                                )
  24:                 ); 
  25:   
  26:             // Expose the service metadata on the metadataAddress
  27:             var smb = new ServiceMetadataBehavior();
  28:             smb.HttpGetEnabled = true;
  29:             smb.HttpGetUrl = new Uri(metadataAddress);
  30:             sHost.Description.Behaviors.Add(smb); 
  31:   
  32:             return sHost;
  33:         } 
  34:   
  35:         public I CreateChannel()
  36:         {
  37:             var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
  38:             var address = new EndpointAddress(String.Format("msmq.formatname:DIRECT=OS:{0}", _queueAddress));
  39:             var channelFactory = new ChannelFactory<I>(binding, address);
  40:             return channelFactory.CreateChannel();
  41:         }
  42:     }
  43:   

This class is perfectly reusable in any project and provide an abstraction on how to create programaticaly WCF services using the msmq binding. To instantiate the class we’ve to pass the interface and his actual implementation. The interface type we’ll be used to create the client & server part. The implementation type (service) will only be used to create the server.
The constructor creates a queue if it’s not already available. Note that the example don’t use security as the transport level security would demand to use active directory. As my pc does not connect to an Active Directory server I had to instantiate the binding without security:

var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);

Not setting this setting resulted to the following error message: ” Binding validation failed because the binding's MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened”

For the dead letter queue I use the default dead letter queue (see comment) settings:

binding.DeadLetterQueue = DeadLetterQueue.System;

To prevent the service to display the namespace as Tempuri.org it’s important to provide the same namespace settings as in your service contract & behavior directive.

binding.Namespace = namespaceName;

The following code exposes the metadata information (wsdl) on the provided metadata address:

var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(metadataAddress);
sHost.Description.Behaviors.Add(smb);

3) Now lets create the message definition.
Add a new class SmsMessage:

public class SmsMessage
{
        public string Number { get; set; }
        public string Body { get; set; }
}

4) Define the service definition:
Add the file SmsService.cs:

   1:  [ServiceContract(Namespace = "http://My.Domain.Services.WCF")]
   2:  [ServiceKnownType(typeof(SmsMessage))]
   3:  public interface ISmsService
   4:  {
   5:      [OperationContract(IsOneWay = true, Action = "*")]
   6:      void SubmitSms(MsmqMessage<SmsMessage> msg);
   7:  } 
   8:   
   9:  [ServiceBehavior(Namespace = "http://My.Domain.Services.WCF")]
  10:  public class SmsService : ISmsService
  11:  {
  12:      public void SubmitSms(MsmqMessage<SmsMessage> msg)
  13:      {
  14:          var sms = msg.Body;
  15:          Console.WriteLine(string.Format(
  16:                                "SMS send to {0} with body='{1}'",
  17:                                sms.Number,
  18:                                sms.Body)
  19:              ); 
  20:   
  21:      }
  22:  }
  23:   

The SmsService class contains the real implementation code. As the purpose of this article is not to demonstrate how to actually send sms messages I didn’t provide the real code here. This demo only output the message on the console.

5) Finally let’s put all the parts together.
Add the following code to the main part of the program:

   1:   static void Main(string[] args)
   2:      {
   3:          //define variables
   4:          const string queueAddress = @".\private$\sms";
   5:          const string metadataAddress = "http://localhost:8000/BackToOwner/gatewayservice/sms";
   6:          const string nameSpaceName = "http://My.Domain.Services.WCF";
   7:          var message = new SmsMessage()
   8:                            {
   9:                                Number = "+322678821",
  10:                                Body = "This is a sample sms message!"
  11:                            };
  12:          var msmqMessage = new MsmqMessage<SmsMessage>(message); 
  13:   
  14:          //define factory 
  15:          var factory = new WcfMsmqFactory<ISmsService, SmsService>(queueAddress); 
  16:   
  17:          //Do the work
  18:          using(var serviceHost = factory.CreateMsmqServiceHost(metadataAddress,nameSpaceName))
  19:          {
  20:              Console.WriteLine("Starting the server...");
  21:              serviceHost.Open();
  22:              Console.WriteLine("Instantiating the client channel...");
  23:              var channel = factory.CreateChannel();
  24:              using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
  25:              {
  26:                  Console.WriteLine("Sending the message...");
  27:                  channel.SubmitSms(msmqMessage);
  28:                  scope.Complete();
  29:              }
  30:              Thread.Sleep(1000);
  31:              Console.WriteLine("Closing the server...");
  32:              serviceHost.Close();
  33:          }
  34:          Console.ReadLine();
  35:      }
  36:  }
  37:   
 

   Running the application should display a console with:
Starting the server...
Instantiating the client channel...
Sending the message...
SMS send to +322678821 with body='This is a sample sms message!'
Closing the server...

The real magic happens here:

var factory = new WcfMsmqFactory<ISmsService, SmsService>(queueAddress);

With this few line of code we’ve instantiated a factory that is able to create the client as the server of our service. The only thing we’ve to pass is the queue address – the rest of the configuration is encapsulated in our Factory class and can be easily reused.   We can provide our factory classes to all the enterprise and create a framework on top of WCF that will standardize and facilitate how WCF is used inside our company.

GVD

kick it on DotNetKicks.com

Visual Studio TextMate Font Black Background

 

 

 

 

 

 

It’s about 2 years now that I use a black background in Visual studio with TextMate inspired font "Monaco" and I still love it. For those who wants to try you can download the fonts and the setting file from my server on http://www.belgianagencies.com/content/Visual Studio 2008_Monaco.zip
Install the fonts by copying the Monaco.ttf to c:\windows\fonts and use the Visual Studio Tools-Import & Export settings wizard to configure the font’s settings.

GVD

View Geoffrey Vandiest's profile on LinkedIn

What is the role of a software architect in an Agile Enterprise?

I’ve defined here under what my vision is on the tasks and responsibilities of a Agile Software Architect role should have in the Enterprise. The Enterprise usualy also  has another role that could be defined as the Enterprise Architect whose role is more strategic and cross project. The list here under is applicable to the first category, the once actively participating in software projects.

Project Tasks

  • Take final responsibility for the quality of the software produced
  • Take the important technical decisions taking all quality aspects of the project into consideration (Cost, Maintainability, Availability, Scalability, Security and all other ty’s)
  • Mesure the quality through metrics and code reviews
  • Enforce changes if quality is not in line with standards
  • Select, in the context of the project, what the software engineering practices should be and how they are applicable for the concrete project
  • Define code coverageCode quality and encouragement of best practices
  • Coaching of and adherence to "Agile" software development principles for module design and implementation
  • Take the lead when building prototypes, common tools, general solutions and reusable components
  • Engage the teams in both defining and executing on such tasks
    The people often best suited to build prototypes are those with knowledge of the intimate details
  • Building reusable components comes from first building usable components
  • Management of common libraries
  • Define based on stakeholders requirements what the Performance, scalability and high-availability requirements are.
  • Interface between technical teams (Service team, Project, Development Center, Quality Assurance…), business stakeholders and development teams on technical matters
  • Coordination with QA and release engineers
  • Integration, performance and load testing strategies
  • Release, migration and upgrade strategies
  • Coaching and working directly with development teams on a regular basis
  • Technical customer to the agile development teams
  • Able to add technical user stories to the product backlog
  • Works directly with the product owners to prioritize and trim the product backlog

Responsabilities

  • Participate in the design of the software engineering process(es)
  • High-level technical vision, planning and documentation
  • Automate and define the tools that support the software engineering process(es)
  • Technical oversight in specific technical domain
    EAI, .Net, Java, Packages, ….

I would like to underline what in my opinion differentiate an agile software architect from how our role is usually perceived.
An Agile software architect doesn’t take part to a project only at its beginning, but during the whole project’s lifecycle to ensure a right implementation of the design and architecture. He also has to keep listening to new requirements to adapt solutions if needed.
Even if I acknowledge that an architect has to step back from his work and the teams’ work, I don’t conceive an architect who would remain far from the implementation team. Indeed, an architect can have to write lines of code (at least to create prototypes), but also has to get his hands dirty with code to validate the quality of what is produced or resolve a particularly technically difficult situation.

Further I would like to refer to some toughts of Martin Fowler expressed in the article by Martin Fowler “Who needs Architect”

http://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf

“architecture is the decisions that you wish you could get right early in a project, but that you are not necessarily more likely to get them right than any other”

“A guide is a more experienced and skillful team member who teaches other team members to better fend for themselves yet is always there for the really tricky stuff.”

I would also recommend the following webcast with again Martin Fowler on the role of an architect in an Agile Organization:http://www.infoq.com/presentations/agilists-and-architects

GVD

View Geoffrey Vandiest's profile on LinkedIn

The 5 Pilars of Unit Testing

 

These are, what I consider to be the 5 most desirable quality attributes of a unit test:
 
1.       Unit tests should be accessible, everyone should be able to run them
Running a unit test should not involve more than getting the source code from a source controller, compile the SUT/Test code and clicking on a button to run all the tests. No configuration should be involved. Your tests should not require to setup external components like a DB or SMTP server. 
 
2.       Unit tests should be repeatable
What is the value of a test you can’t trust? Unit tests results should only change when modifications are introduce in the SUT. When the SUT remain the same the unit tests should always return the same result. Therefore unit tests should be state independent and in anyway they should never be dependant on a shared resource like a file or persistent memory.
 
3.       Unit tests should be easy to write and maintain
In an software shop we should only use a practice or tool when this is economical viable meaning that the cost of writing the tests and maintaining it should not exceeds the costs of having a bug and fixing it. To minimize the cost of creating and maintaining tests we should use appropriate practices and tools. We should also have the same quality requirement for test code as for production code. Refactoring is as important for test code as for production code.   
 
4.       Unit tests should be resistant to change
We should write our test in such a way that the amount of tests failing when introducing a change is minimal. When testing the SUT it is common to set his variable in proper state so it can be tested. This type of setup test code is very fragile. We should always try to isolate this type of code so it is easy to change. 
 
5.       Unit tests should run quickly
ideally unit tests should be executed after every build. Having to wait more than 1 minute to execute all the unit tests will decrease the overall productivity of the tests. Unit tests should never be dependant on costly resources to invoke like web services or DB.
 
Is there someting missing here? 
 
GVD
 
View Geoffrey Vandiest's profile on LinkedIn
 

Extensibility for ASP.NET MVC

 

I’m working on an extensibility framework made to be used on top of ASP.NET MVC. My extensibility framework is based on the famous Ioc container: Structuremap .
The use case I’m trying to fulfill is simple: create an application that should have some basic functionality that can be extended for every customer (=multi-tenancy). There should only be one instance of the application hosted but this instance can be adapted for every customer without making any changes to the core website.
I was inspired by the article on multi tenacy wroted by Ayende Rahien: http://ayende.com/Blog/archive/2008/08/16/Multi-Tenancy--Approaches-and-Applicability.aspx Another source of inspiration was the book of Eric Evans on Domain Driven Design. My Extensibility framework is based on the repository pattern and the concept of root aggregates. To be able to use the framework the hosting application should be build around repositories and domain objects. The controllers, repositories or domain objects are bind at runtime by the ExtensionFactory.
A plug-in is simply an asselmbly that contains Controllers or Repositories or Domain Objects that respects a specific naming convention. The naming convention is simple, every class should be prefixed by the customerID e.g.: AdventureworksHomeController.
To extend an application you copy a plug-in assembly in the extension folder of the application. When a user request a page under the customer root folder e.g: http://multitenant-site.com/[customerID]/[controller]/[action] the framework check if there is a plug-in for that particular customer and instantiate the custom plug-in classes otherwise it loads the default once. The custom classes can be Controllers – Repositories or Domain Objects. This approach enables to extend an application at all levels, from the database to the UI, through the domain model, repositories.
When you want to extend some existing features you create a plug-in an assembly that contains subclasses of the core application. When you’ve to create totally new functionalities you add new controllers inside the plug-in. These controllers will be loaded by the MVC framework when the corresponding url is requested. If you want to extend the UI you can create a new view inside the extension folder and reference the view by a new or subclassed controller .To modify existing behavior you can create new repositories or domain objects or sub classing exiting ones. The framework responsibility is to determine which controller/ repository / domain object should be loaded for a specific customer.
I advise to have a look at structuremap (
http://structuremap.sourceforge.net/Default.htm) and especially at the Registry DSL features http://structuremap.sourceforge.net/RegistryDSL.htm .
This is the code I use at the startup of the application to register all plug-in controllers/repositories or domain objects:
protectedvoidScanControllersAndRepositoriesFromPath(string path)
{
   
this.Scan(o =>
    {
       o.
AssembliesFromPath(path);
       o.
AddAllTypesOf<SaasController>().NameBy(type => type.Name.Replace("Controller", ""));
       o.
AddAllTypesOf<IRepository>().NameBy(type => type.Name.Replace("Repository", ""));
       o.
AddAllTypesOf<IDomainFactory>().NameBy(type => type.Name.Replace("DomainFactory", ""));
       });
}
I also use an ExtensionFactory inheriting from the System.Web.MVC. DefaultControllerFactory. This factory is responsible to load the extension objects (controllers/registries or domain objects). You can plugin your own factories by registering them at startup in the Global.asax file:
protectedvoid Application_Start()
{
   
ControllerBuilder.Current.SetControllerFactory(
      
newExtensionControllerFactory()
    );
}
l'll try to find some time to explain my approach more clearly on my blog and hopefully I'll be able to publish my Extesnsibility framework on CodePlex soon.

Is mangling PRINCE2 and SCRUM Agile?

This week I attended a session of the Agile users-group in Belgium. The topic was about: how to mangle SCRUM and PRINCE2. 

The discussions were held following the fishbowl technique. The advantage of  this technique is that it allows the entire group to participate in a conversation.   Five chairs were put in the middle, this was the fishbowl and the rest of the people attending the event were arranged in concentric circles outside the fishbowl. Any member of the audience could, at any time, occupy the empty chair and join the fishbowl. The concept was a real success as everyone went at least once inside the fishbowl.
Interesting thoughts were exchanged. This is what I personally will keep from this evening:
Because PRINCE2 isn’t prescriptive about how the implementation will be performed it perfectly fit with AGILE methodologies. If your management is reluctant to try Agile methodologies like SCRUM you can refrain their fears by using PrinCE2 as a harness for SCRUM. The project manager and the higher management can use PRINCE2 as a governance framework while the developers and testers can use SCRUM practices and values. 
 The risk is to generate a lot of waste. As PRINCE2 is highly document driven your team and especially the project manager will have to generate lots of documents that are not really adding value to an agile team. Another risk is that your whole team would break apart. Developers will naturally tend to adopt the Agile principles and values and the chickens (PM & Customer & Management) will be more comfortable with Prince2. The danger is that the 2 groups will use different vocabulary leading to confusion. The two groups will be less cohesive and you risk ending with the worst of both worlds.
My advice is that you should try to stick to the pure Agile values and practices but if you’re really forced to adopt Prince2, fake it! Prince2 prescribe a min. set of doc and practices, simply adopt this min. set and do the less possible.
 

First Steps with Unit Testing Walkthrough

 In this article I introduce through a walkthrough the basics of how to write a good well structured unit test. This post is the first of a series about Unit testing and TDD. I’ll not be doing TDD for now because I first want to start with the basics of creating well structured unit tests.  In later posts we will build on this to practice TDD. Therefor the tests of this first walkthrough will seem overly simple, but let’s crawls before we start running.
The details on how we should write tests vary with the programming framework & unit test framework. For this walkthrough I've choosen to implement  the tests and examples witrh C# and VSTS .Nevertheless the core principle of how to implement automated tests stays applicable in any technology.  If you desire to get the walkthroughs for NUnit or for other programming frameworks post a demand in this blog.  You can download the completed walkthrough project here.

 


public class Fleet : IDisposable
{
private List _planes { get; set; }

public Fleet()
{
this._planes = new List();
}

public Plane this[string index]
{
get
{
return this._planes.Find(p => p.Name == index);
}
}

public void Add(string name)
{
this._planes.Add(new Plane(name));
}


public int Count
{
get
{
return this._planes.Count;
}
}

public void Dispose()
{
this._planes = null;
}
}

public class Plane
{
public Plane(string name)
{
this.Name = name;
}

public int PlaneID { get; set; }
public string Name { get; set; }

}






Examine the code of Fleet and Plane. The Fleet class represents an aero fleet (a simple Model) this class is a sort of collection of planes. The fleet class contains a property “Count” that counts the number of planes in the fleet.
Create a new Test Project File, right click solution, add, new, Project, select C#, Test, name your Project:”FirstStepsTest”.
Launch all tests: Ctrl R,A or Test, Windows, Test View
VS should launch the TestMethod1 and it should pass.










 Replace the generated TestMethod() with the following test:


[TestMethod()]
public void NewFleet_WithNoPlanes_CountWillReturn0()
{
   //Setup
  Fleet fleet = new Fleet();

  //Execute
  int actual = fleet.Count;

  //Verify
  Assert.AreEqual(0, actual);
}

Run the test by right click on the test name and select “Run Test”.
The test above is a public method whose giving the attribute [TestMethod] the test class itself is been annotated with the attribute [TestClass]. This enable the testRunner of VSTS to retrieve all test methods.

Every test will always consist of 3 parts:
• The setup: to be able to test our SUT we’ve to put him in a certain state so it can be tested.
• The test execution: when our SUT is prepared to be test we can call the actual execution unit on our SUT.
• The verification: A test generally ends with the comparison on the expected results and the actual outcome of our execution.

The last part of our test uses an assertion method of our unit testing framework. Knowing what to assert about in your tests is pretty much 90% of the battle. An assertion is basically taking an expected value and comparing it to an actual value. If the expected value does not match the actual value, then the test will fail.

There are many other type of assertions but for simplicity and for readability when debuging I prefer to only use the Assert.Equals(). Assert equals is the most generic form of assertion and it will always display a meaningful message like Assert.AreEqual failed. Expected:. Actual:.Add following new tests to the test class:

 


[TestMethod()]
public void Add_OnePlane_WillIncrementCountByOne()
{
//Setup
Fleet fleet = new Fleet();

//Execute
fleet.Add("X2938");

//Verify
Assert.AreEqual(1, fleet.Count);
}

[TestMethod()]
public void RetriveByIndex_APlane_WillReturnThePlane()
{
//Setup
Fleet fleet = new Fleet();
fleet.Add("X2938");

//Execute
String actual = fleet["X2938"].Name;

//Verify
Assert.AreEqual("X2938", actual);
}



Examine the tests and run them, they should all pass.

We'll refactor a little bit our code because the test contains some parts of code that are repeated and repeating ourselves is always bad!
First we will remove the magic string: “X2938” and will instantiate a string field flightName containing this value. Replace “X238” with this new variable.
We will also promote the fleet object in each test to a new private field. We will use the [TestInitialize] attribute to instantiate this field.
Also imagine that our Fleet class implements IDisposable because it uses somehow an expensive resource that isn’t automatically disposed by the garbage collector. We could call fleet.Dispose() after the Assertion but what if our test fails? The dispose method would never been called and the object will remain in memory.
The result should look like that:
 


[TestClass]
public class FleetTest
{
private Fleet fleet;
const string flightName = "X2938";

[TestInitialize()]
public void TestInitialize()
{
fleet = new Fleet();
} [TestCleanup()] public void TearDown() { fleet.Dispose(); }

[TestMethod()]
public void NewFleet_WithNoPlanes_CountWillReturn0()
{

//Execute
int actual = fleet.Count;

//Verify
Assert.AreEqual(0, actual);
}

[TestMethod()]
public void Add_OnePlane_WillIncrementCountByOne()
{

//Execute
fleet.Add(flightName);

//Verify
Assert.AreEqual(1, fleet.Count);
}

[TestMethod()]
public void RetriveByIndex_APlane_WillReturnThePlane()
{
//Setup
fleet.Add(flightName);

//Execute
String actual = fleet[flightName].Name;

//Verify
Assert.AreEqual(flightName, actual);
}
}



We've defined a SetUp() and TearDown() pair of methods. In major XUnit frameworks, these are used to create Fixtures. A Fixture is some resource all tests in a test case have in common and which sets the context of the test (the situation in which we're testing), as well as other repetitive objects or resources.
VSTS uses the attributes [TestInitialize()] for the Setup, this part is run before each test and [TestCleanup()] for the teardown, run after each test.
Because each test must be isolated (cannot share information) these methods will tell the Framework to create our Fixture (a Fleet instance) before each test, and destroy it after. So each test gets a shiny new version to play with, free of anything a previous test may have done.

The test case above is a good small start and I hope you enjoyed this first walkthrough on unit testing, don’t hesitate to post some feedback!

 

View Geoffrey Vandiest's profile on LinkedIn

ASP.NET Web setup project walkthrough

 
 
This post contains a walkthrough that will help you understand the basic tasks to accomplish to create an MSI packages for deploying your web application. The walkthrough describes the most common scenario of deploying a web project.  We will create a standard Web setup project.  This project will generate as output an msi package that will create and configure the application IIS and copy the application’s file to a specific location on the server.   This walkthrough also describes how to modify the web.config file for providing a connectionstring or change any of the configuration sections. 
Because msi packages are mostly deployed by system engineers from the command line, this walkthrough will also pay attention on how to enable quiet installs and how to pass parameters to the installer from the command line.
 

1.     Create a “Hello World” web service


To be able to create a setup will need a sample project that will be deployed by the setup project.  So we create a new empty ASP.NET website application.
- File->new ->ASP.NET WebService
image001
 
Add  a Class library project to your solution.
- File->Add->Class Librrary
image003
 
 
Now we should have 2 projects inside our solution.
- Add a static method SayHello() to the class1.
image006 
 
 
 
Reference this class in your web service project:
- Add Reference-> Projects->SayHelloLibrary
 image007
 
 
 
- Change the code of the Hello world method to use the Library static method SayHello()
 image010
 
 
 
- Hit F5, your solution should compile. 
- Test the application through the invoke button of the test web page, you should see the following:
 image011
 
 

2.     Add a Web setup project


We will add the web setup deployment project to the solution.
- File->Add->New Project->Other Project Types->Web Setup Project
image013
 
 
Now our solution should look like this:
 image016
 
 
Now the real work begins, we will configure our web setup project to hold our content and our compiled assemblies.
  
 

3.     Add content and assemblies to your web setup project

 
First we will add the content of our web service project.  These are the asmx pages and the content of the APP_CODE folder.  They will be compiled by the host IIS server the first time the site will be hit.
 
Right click on the setup project->Add->Project output.
image018
 
 
 
A “Add project output Group” dialog box should appear.
image019
 
 
 
 
Because our Web setup project does not have any compiled assemblies as output we only can select “Content Files”.   
 image022
 
 
You should be in the file system view. If you don’t see the above screen.
-  right-click on the web project setup folder and choose view->File system.
Now we will add our web service application compiled assemblies. 
- Right-click again on the web-setup project and choose Add->Project Output and select the SayHelloLibrary project and click on “Primary Output”.
image025 
 
 
After we click on the ok button Visual studio has added the “Primary Output” to the root of the Web Application Folder. This will result in a compile error the first time we try to hit the application we deploy.
To correct this error we must move the “Primary output” to the Bin folder of our web application. 
- Simply drag & drop the “Primary Output” to the bin folder.
image027
image029 
 
 
Before we test our first installation package we’ve to compile it because Visual studio will not compile it as part of the solution. When we compile our project, visual studio will generate an msi file containing all parts of our application.
It’s time to test our first installation packet. 
- Select the setup project->richt-click->Install
image031 
 
 
 
The setup wizard pops-up, click next.
image033 
 
 
You can change the default value of the  Virtual directory textbox.  The default Virtual Directory is a property of your “Web application folder” available in the File system view.  Important: If you want to be able of passing the virtual directory as a parameter through the console for a quiet installation you should set this property to a blank field otherwise the msi package will overwrite a blank value with the value of the property.
When the installation is completed successfully the web service should be available on the your local IIS server under the path http://localhost/HelloWorldSetup/service.asmx
image035 
 
 
The application should also be visible in the “Add or Remove Programs” in the Windows Control Panel.
image037 
  
 
 
 

4. Adapt the connectionString property of the Web.Config file.
 
The web setup project wizard alow us to change common IIS settings through the File System view (View->File System) by changing the properties of the “Web Application Folder”. 

image039 
 
 
 
We can also add prerequisits of our solution (the .net framework2 is a standard prerequisit).
To adapt the connectionString property of our Web.Config file we will have to add custom code to our project that will edit the config file.  To be able to this type of actions during a setup we’ve to create custom actions.  Custom actions are code that is executed during the installation process.  Therefore we’ve to create a new ClassLibrary project. 
- Add a classlibrary project and name it HelloWorldCustomActions.
- Add following assemblys references: System.Configuration.dll,
image041
 
 
 
System.Configuration.Install.dll, System.Web.dll.
- Add a new class to MyCustomAction.cs your project that will be used during the installation of your project.    This class must inherit from “System.Configuration.Install.Installer” class and be annotated with the RunInstaller(True) attribute. using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration.Install;
using System.ComponentModel; 
namespace HelloWorldCustomActions
{   
  [RunInstaller(true)]   
  publicclassMyCustomAction:Installer   
  {       
    publicoverridevoid Install(System.Collections.IDictionary stateSaver)       
    {            base.Install(stateSaver);       
    }   
 }
}
 
 
Now we need to create our custom action and associate it with our class.
First we need to add the output of the HelloWorldCustomActions assembly in our Setup project.
- Right-click “HelloWorldSetup” project->Add->Primary Output
image044 
 
 
- From the File System View move the “Primary output from HelloWorld actions” to the bin folder.
Now we will make sure that our code is executed as a custom action during the installation.
- Right-click the project folder->view->CustomActions.
The Custom action view should be displayed.
- Right-click on the install folder->Add Custom Action->select “Primary output from HelloWorldCustomActions (Active)”.
 
image046 
 
 
The web setup project wizard contains a form where the user must select the application site and the virtual directory. To be able to locate and change the web.config file of our application we need to read these parameters.  We can also pass these arguments by the command line and provide a targetdirectory. 
To be able to access these parameters we need to declare them in the “CustomActionData” property of our CustomAction: 
- Select your custom action->In the property window select “CustomActionData” Insert the following values:
/targetdir="[TARGETDIR]\" /targetvdir="[TARGETVDIR]" /targetsite="[TARGETSITE]" /targetconn="[EDITA1]"  /db="[DB]"
 
image048
 
 
 
We will now add a screen to our wizard that prompts the user for a connectionString. 
- Right click the project->View ->User Interface.
- Right click start-> Add Dialog
image050 
  
 
- Select Textboxes(A) and move it between “Installation Address” and “Confirm Installation”.
- Set the following properties:
 
image054 
 
Now we will code our custom action.
- First check you have following references in you CustomAction project.
image056 
  
 
- Set following using statements in your CustomAction class:
using System;
using System.Configuration;
using System.Configuration.Install;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.DirectoryServices;
using System.Web.Configuration;
using System.Windows.Forms;
 
 
 
your install method should look like:
 
 publicoverridevoid Install(System.Collections.IDictionary stateSaver)       
{            base.Install(stateSaver);
              // Retrieve configuration settings            string targetSite = Context.Parameters["targetsite"];
            string targetVDir = Context.Parameters["targetvdir"];
            string targetDirectory = Context.Parameters["targetdir"];
string targetConnectionString = Context.Parameters["targetconn"];
            //if this is a quiet install //the connectionstring is passed as with a parameter named "db"
            if (targetConnectionString.Length < 1)                targetConnectionString = Context.Parameters["db"];
              if (targetConnectionString.Length < 1)thrownewInstallException("Please provide a connectionstring!");
              if (targetSite == null)thrownewInstallException("IIS Site Name Not Specified!");
              if (targetSite.StartsWith("/LM/"))                targetSite = targetSite.Substring(4);  ConfigureWebConfig(targetSite, targetVDir, targetConnectionString);
          } 

Add the ConfigureWebConfig method:
 void ConfigureWebConfig(string targetSite, string targetVDir, string targetConn)       
{            // Retrieve "Friendly Site Name" from IIS for TargetSite
            DirectoryEntry entry =                 newDirectoryEntry("IIS://LocalHost/" + targetSite);            string friendlySiteName =                 entry.Properties["ServerComment"].Value.ToString();
              // Open Application's Web.Config            Configuration config =                 WebConfigurationManager.OpenWebConfiguration("/" + targetVDir, friendlySiteName);
              addConnectionStringAttribute(targetConn, config);            togleCompilationAttribute(config);
              // Persist web.config settings            config.Save();
 
        }
 
Method to add the connectionstring to your web.config:
privatestaticvoid addConnectionStringAttribute(string connectionStringValue, Configuration config)       
{            ConnectionStringSettings appDatabase = newConnectionStringSettings();
            appDatabase.Name = "db";            appDatabase.ConnectionString = connectionStringValue;
            appDatabase.ProviderName = "System.Data.SqlClient";
              config.ConnectionStrings.ConnectionStrings.Clear();
            config.ConnectionStrings.ConnectionStrings.Add(appDatabase);
 
        }

This method will set the compilation attribute to debug=false
privatestaticvoid togleCompilationAttribute(Configuration config)       
{            CompilationSection compilation;            compilation = config.GetSection("system.web/compilation") asCompilationSection;
              if (compilation != null)                compilation.Debug = !compilation.Debug;
           
        }
Now you can test your installation package. 
- Right-click Setup project->Install.

The second screen should ask for a connectionstring.
image061 
 
 
 
5.     Quiet install
 
When distributing a setup package you will mostly install the application through a quiet install.  Therefore you’ve to pass the parameter through the command line.   I experienced that the parameters you pass through the console are sometimes overwritten by the parameters you’ve added in your custom screens.  This is why I added a supplementary parameter “db” and don’t use the parameter “targetconn”.  The installer first checks if the parameter is empty.  This will be the case if you install the application through a quiet install. 
You will find this parameter in the CustomactionData property of the custom action:
/targetdir="[TARGETDIR]\" /targetvdir="[TARGETVDIR]" /targetsite="[TARGETSITE]" /targetconn="[EDITA1]"  /db="[DB]"
 The code that handles the parameter in the Install method:
if (targetConnectionString.Length < 1)
                targetConnectionString = Context.Parameters["db"];
You can launch the msi setup package with the folowing command line: (First navigate to the directory containing the builded release version of the msi)
>HelloWorldSetup.msi /qb targetvdir="HelloWorld" db="Test for connectionstring"
If you want to specify the target website you need to specify the website IIS metabase targetsite path.  This path mostly begins with “/LM/W3SVC/” followed by the site id. 
A trick to find the site id or to debug the setup application is to use the /l* option.  Launch the installer with the /l* option and follow the wizard.  The /l* will log all the parameters passed to the installation program.  After the installation completes you can retrieve website metabase path by searching for the “targetsite” in the log file.
>HelloWorldSetup.msi /l* log.txt
I hope this tutorial help you to understand the basics of creating a web setup project.  This type of setup will enable you creating testable and repeatable deployment scenarios.  It will also help our IT engineers to deploy web applications gracefully on production machines.
 
GVD

View Geoffrey Vandiest's profile on LinkedIn