Wednesday, May 26, 2010

Test Driven Development Tutorial in C# 4.0

Posted on/at 1:27 AM by Admin

Introduction - Defining the Battlefield
This tutorial is an short introduction to using Test Driven Development (TDD) in Visual Studioclip_image001 2010 (VS2010) with C#. Like most of my examples it's based on a game. 
By completing this tutorial you will:

  • Get a taste of TDD through a series of small iterations;
  • Learn how VS2010 provides TDD support through a number of new features; and
  • Learn a number of C# 4.0 features.

CannonAttack is a simple text based game in which a player enters an angle and velocity of a cannonball to hit a target at a given distance. The game uses a basic formula for calculating the trajectory of the cannonball and the player keeps taking turns at shooting at the target until it has been hit. I won't go into TDD theory in any great detail now, but you should check out the number of great references to TDD including:
http://en.wikipedia.org/wiki/Test_driven_development
http://www.codeproject.com/KB/dotnet/tdd_in_dotnet.aspx
C# .NET 2.0 Test Driven Development by Matthew Cochran
http://msdn.microsoft.com/en-us/library/dd998313(VS.100).aspx
The following are the fundamental steps of a TDD iteration:

  • RED - take a piece of functionality and build a test for it and make it fail the test by writing a minimum amount of code(basically just get it to compile and run the test);
  • GREEN - write minimal code for the test to make it succeed; and
  • REFACTOR - clean up and reorganize the code and ensure it passes the test and any previous tests.

In this tutorial we will be progressing through a number of iterations of the TDD cycle to produce a fully functional simple application. Each iteration will pick up one or more of the requirements/specs from our list (see The CannonAttack Requirements/Specs below). We won't test for absolutely everything and some of the tests are fairly basic and simplistic, but I am just trying to keep things reasonably simple at this stage
VS2010 and C# 4.0:
This tutorial covers the use of VS2010 and targets a number of features of C# 4.0,

  • Generating stubbs for TDD in VS2010;
  • Test Impact View in VS2010;
  • Tuples; and
  • String.IsNullOrWhiteSpace method.

There are many more features of C#4.0 and we will be covering them in future tutorials.
What you need:

  • This is a C# tutorial so a background in C# would be very useful; and
  • VS 2010 professional or above (This tutorial has been tested against VS2010 rtm and beta2).

The CannonAttack Requirements/Specs:
The following is a combination of Requirements and Specifications that will give us some guide in terms of the application we are trying to build:

  • Windows Console Application;
  • Player identified by an id, default is set to a constant "Human";
  • Single player only, no multi-play yet;
  • Allow player to set Angle and Speed of the Cannon Ball to Shoot at a Target;
  • Target Distance is simply the distance of the Cannon to Target, and is created randomly by default but can be overridden;
  • Angle and Speed needs to be validated (specifically not greater than 90 degrees and Speed not greater than speed of light);
  • Max distance for target is 20000 meters;
  • Base the algorithm for the calculation of the cannons trajectory upon the following C# code (distance and height is meters and velocity is meters per second):
    distance = velocity * Math.Cos(angleInRadians) * time;
    height = (velocity * Math.Sin(angleInRadians) * time) - (GRAVITY * Math.Pow(time, 2)) / 2;
  • A hit occurs if the cannon is within 50m of the target;
  • Display number of shots for a hit
  • Game text will be similar to following:

Welcome to Cannon Attack
Target Distance:12621m
Please Enter Angle:40
Please Enter Speed:350
Missed cannonball landed at 12333m
Please Enter Angle:45
Please Enter Speed:350
Hit - 2 Shots
Would you like to play again (Y/N)
Y
Target Distance:2078m
Please Enter Angle:45
Please Enter Speed:100
Missed cannonball landed at 1060m
Please Enter Angle:45
Please Enter Speed:170
Missed cannonball landed at 3005m
Please Enter Angle:45
Please Enter Speed:140
Hit - 3 shots 
Would you like to play again (Y/N)
N
Thanks for playing CannonAttack

OK so now we are ready to code, let's go...
Iteration 1 - Creating the Cannon
Steps

  • Start Visual Studio
  • Click New Project...
  • From the Windows submenu select Console Application as below
    clip_image002
  • Call the application CannonAttack and click OK
  • Right click on Program.cs and select Rename and call the file CannonAttack.cs.
  • If you see the following select YES.
    clip_image003
  • When the solutionclip_image001[1] has loaded right click on the solution in Solution Explorer and select ADD->NEW PROJECT. If you can't see the Solution Explorer select from Tools->Options->Projects and Solutions and tick always show solution
  • Select Test Project and call it CannonAttackTest as below:
    clip_image004
  • Click OK
  • Right click on the CannonAttackTest project and make it the startup project by selecting Set as Startup Project.
  • Rename the UnitTest1.cs to CannonAttackTest.cs
  • If you see the following select YES 
    clip_image003[1]
  • You should see the Solution explorer appear as:
    clip_image005
  • Open the code window for the CannonAttackTest.cs file and you should see the default test method. The [TestMethod] attribute above a method in this file indicates VS2010 will add this method as a unit test.
  • Replace the default test method:
    [TestMethod]
    public void TestMethod1()
    {
    }
    with the following:
    [TestMethod]
    public void TestCannonIDValid()
    {
    Cannon cannon = new Cannon();
    }
  • This won't compile but right click on Cannon and select Generate->New Type
  • When the following screen appears change the Project to CannonAttack and accept the other defaults as below:
    clip_image006
  • Now change the TestCannonIDValid method to:
    [TestMethod]
    public void TestCannonIDValid()
    {
    Cannon cannon = new Cannon();
    Assert.IsNotNull(cannon.ID);
    }
  • Now the solution won't compile as the ID property does not exist
  • Right click on the ID and select Generate->Property (ID has now been added to the Cannon class). This creates an auto property which for the moment will hopefully compile.
  • Save all projects and hit CTRL-F5. This will start the Tests running (not F5 in debug mode because debug mode will by default stop if an Assert fails).
  • You should see in the tests window:
    clip_image007
  • The test failed. This is correct and as expected the first phase of the TDD iteration has occurred RED - failed!!!
  • So now that we have a red lets get this test to pass.
  • Select cannon.cs in the CannonAttack project and make the following change to the ID property:
    public string ID
    {
    get
        {
    return "Human";
        }
    }
  • Now run the test CTRL-F5 and we should see:
    clip_image008
  • We have just completed the second stage of a TDD cycle GREEN - Pass!!!!
  • So the next stage is to refractor, and it would be nice to make a couple of changes to the class to clean it up, so that the class now looks like:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    namespace CannonAttack
    {
    public sealed class Cannon
        {
    private readonly string CANNONID = "Human";
    private string CannonID;
    public string ID
            {
    get
                {
    return (String.IsNullOrWhiteSpace(CannonID)) ? CANNONID : CannonID;
                }
    set
                {
                    CannonID = value;
                }
            }
        }
    }

We have made this class sealed so that it is not inherited by anything. Also, we have added a readonly string to store a default ID if not set by the user. I am going to use runtime constants (readonly) because they are more flexible than compile time constants (const) and if you are interested check out Bill Wagner's book (effective C# - 50 Ways to Improve your C#) for further details.
Let's run the test again. Again it should compile and pass tests because although we have made some changes to the code, we should not have impacted the tests and this is an important part of the Refactor phase. We should make the changes we need to make the code more efficient and reusable, but it is critical that the same test that we made pass in the Green phase still passes in the Refactor phase.
The refactoring is complete. Now for ITERATION 2 of the CannonAttack project.
Iteration 2 - One Canon, and only one Cannon - Using the Singleton Pattern.
Like the previous iteration we will pick an element of functionality and work through the same sequence again RED->GREEN->REFACTOR. Our next requirement is to allow only a single player. Given that we can allow 1 player we really should only use one instance, let's create a test for only one instance of the cannon object. We can compare two objects to ensure they are pointing at the same instance like (obj == obj2).

  • Add a new test beneath the first test in cannonattacktest.cs and our method looks like:
    [TestMethod]
    public void TestCannonMultipleInstances()
    {
    Cannon cannon = new Cannon();
    Cannon cannon2 = new Cannon();
    Assert.IsTrue(cannon == cannon2);
    }
  • Run the tests by hitting CTRL-F5. We 1 Pass and 1 fail (our new test) so we are at RED again.
    clip_image009
  • The reason that this failed is we have created two different instances. What we need is the singleton pattern to solve our problem. I have a great book on patterns called HEAD FIRST DESIGNclip_image001[2] PATTERNS if you want to know more about design patterns it's a great start - sure its Java but the code is so close to C# you should not have any real problems.
  • We are going to use the singleton pattern to meet the requirement of a single player. Really we don't want multiple instances of cannons hanging around - 1 and only 1 instance is needed. Insert the following Singleton code below the property for the ID. 
    private static Cannon cannonSingletonInstance;
    private Cannon()
    {
    }
    public static Cannon GetInstance()
    {
    if (cannonSingletonInstance == null)
        {
            cannonSingletonInstance = new Cannon();
        }
    return cannonSingletonInstance;
    }
  • If we try to run the tests we won't compile because the cannon object can't be created with Cannon cannon = new Cannon(); So make sure that we use Cannon.GetInstance() instead of new Cannon(). The two test methods should now look like:
    [TestMethod]
    public void TestCannonIDValid()
    {
    Cannon cannon = Cannon.GetInstance();
    Assert.IsNotNull(cannon.ID);
    }
    [TestMethod]
    public void TestCannonMultipleInstances()
    {
    Cannon cannon = Cannon.GetInstance();
    Cannon cannon2 = Cannon.GetInstance();
    Assert.IsTrue(cannon == cannon2);
    }
  • Run the Tests again CTRL-F5
    clip_image010

This time they pass GREEN so time to refactor. We are going to change our Singleton code because although the code works (and is pretty much 100% the same as the singleton code in the HEAD FIRST DESIGN PATTERNS Book) it is not thread safe in C# (see http://msdn.microsoft.com/en-us/library/ff650316.aspx) So we replace the original singleton code with:

private static Cannon cannonSingletonInstance;
static readonly object padlock = new object();
private Cannon()
{
}
public static Cannon GetInstance()
{
lock (padlock)
    {
if (cannonSingletonInstance == null)
        {
            cannonSingletonInstance = new Cannon();
        }
return cannonSingletonInstance;
    }
}
The block inside the lock ensures that only one thread enters this block at any given time. Given the importance of determining if there is an instance or not, we should definitely use the lock.

  • Run the all the tests again CTRL-F5 and they should all pass

That's the end of the second iteration and I think you should be getting the hang of it by now, so lets get onto the 3rd iteration.
Iteration 3 - Angling for something...
We will add another test method. This time we want to ensure that an incorrect angle (say 95 degrees) will not hit. So we need a Shoot method and a return type (lets keep it simple and make it a Boolean for now).

  • Add the following test below the last test:

[TestMethod]
public void TestCannonShootIncorrectAngle()
{
Cannon cannon = Cannon.GetInstance();
Assert.IsFalse(cannon.Shoot(95, 100));
}

  • Of course the compiler will complain and we get it to compile by right clicking on the Shoot method and select Generate->Method Stub.
  • Change the return type of the stub (in Cannon.cs) to a bool so that it will compile.

public bool Shoot(int p, int p_2)
{
throw new NotImplementedException();
}

  • Now hit CTRL-F5 and we see that the first two tests should still pass but our new test fails as this is the RED phase again.
  • So open Cannon.cs in the CannonAttack project, and replace the generated Shoot method with:

public bool Shoot(int angle, int velocity)
{
if (angle > 90 || angle < 0) //Angle must be between 0 //and 90 degrees
    {
return false;
    }
return true; //Not going to do the calculation just yet
}

  • Run the tests again and all three tests now pass so again :GREEN, so now back to refactor.
  • We need to add two extra readonly integers to the class. Insert them at the top of the class. We will add them as public so that they are exposed to the console application eventually.
    public static readonly int MAXANGLE = 90;
    public static readonly int MINANGLE = 1;
  • We want to refactor the Shoot method, so this now looks like:
    public Tuple<bool, string> Shoot(int angle, int velocity)
    {
    if (angle > MAXANGLE || angle < MINANGLE) //Angle must be //between 0 and 90 degrees
        {
    return Tuple.Create(false, "Angle Incorrect");
        }
    return Tuple.Create(true, "Angle OK"); //Not //going to do the calculation just yet
    }
    We have changed the interface of the method so it returns a Tuple indicating if its a hit (BOOL) and also a message (STRING) containing the display text. The Tuple is a feature of C# 4.0. used to group a number of types together and we have used it in conjunction with the type inference of the var to give a neat and quick way to handle the messages from our shoot method. See the following article for further information:http://www.davidhayden.me/2009/12/tuple-in-c-4-c-4-examples.html
  • To handle the change to the shoot method we change our test to:

[TestMethod]
public void TestCannonShootAngleIncorrect()
{
var shot = cannon.Shoot(95, 100);
Assert.IsFalse(shot.Item1);
}
You will also notice now we have removed the object initialization of the cannon in our test method. The reason we have done this is we have moved that to the Class Initialize method of CannonAttackTest.cs. To do this simply uncomment out the two lines below:

[ClassInitialize()]
public static void CannonTestsInitialize(TestContext testContext)
{
}

Rename MyClassInitialize to CannonTestsInitialize.

  • Now just declare a cannon object for the class and add the object initialize code as this method is called every time we run our test. It means every test can remove that one line of code and now looks like the following (note we have removed a number of commented test methods that visual studio creates by default):

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CannonAttack;
namespace CannonAttackTest
{
    [TestClass]
public class CannonAttackTest
    {
private static Cannon cannon;
        [ClassInitialize()]
public static void CannonTestsInitialize(TestContext testContext)
        {
            cannon = Cannon.GetInstance();
        }
        [TestMethod]
public void TestCannonIDValid()
        {
Assert.IsNotNull(cannon.ID);
        }
        [TestMethod]
public void TestCannonMultipleInstances()
        {
Cannon cannon2 = Cannon.GetInstance();
Assert.IsTrue(cannon == cannon2);
        }
        [TestMethod]
public void TestCannonShootAngleIncorrect()
        {
var shot = cannon.Shoot(95, 100);
Assert.IsFalse(shot.Item1);
        }
    }
}

  • Now let's compile and run the tests CTRL-F5 and we'll find that they should all pass so we are finished the 3rd iteration.

Iteration 4 - That's a pretty fast cannonball
The next area of functionality, looking at the requirements, is to validate the incorrect speed. Just incase you are worrying about this validation...
"Nothing in the universe can travel at the speed of light, they say, forgetful of the shadow's speed." ~Howard Nemerov
Now that we are informed, let's write the test...

  • Add the following below the TestCannonShootAngleIncorrect method

[TestMethod]
public void TestCannonShootVelocityGreaterThanSpeedOfLight()
{
var shot = cannon.Shoot(45, 300000001);
Assert.IsFalse(shot.Item1);
}

  • So we run the tests and it will fail RED because the validation isn't complete in the Shoot method . We add the code needed into shoot method just under the validation code for the incorrect angle:

if (velocity > 300000000)
{
    return Tuple.Create(false, "Velocity of the cannon cannot travel faster than the speed of light");
}

  • Run the tests again and this time they all pass - GREEN
  • Time to refactor, but this time lets use a new feature in VS2010 that allows us to determine the impact of a code change on the Test project.
  • Select from the menu TEST->Windows->Test Impact View :
    clip_image011
  • The Test Impact View will appear on the right of your IDE and if you haven't used Test Impact View yet you will see:
    clip_image012
  • Click the Enable test impact data collection in the active test settings link and then select OK on the next dialog. You must do this for each solution you use test impact view.
  • Build and Run CTRL-F5 all the tests and again they should all pass. Time to refactor.
  • Now add a constant (readonly int) for the speed of light and then ensure the code in the shoot method refers to the constant ie:
    private readonly int MAXVELOCITY = 300000000;
    And
    if (velocity > MAXVELOCITY)
    {
        return Tuple.Create(false, "Velocity of the cannon cannot travel faster than the speed of light");
    }
  • Now build the project and have a look at the Test Impact View:
    clip_image013

This is very useful as we can see the impact of that change (even though its not a serious change) on the tests. If you want to run just the tests impacted by the change click on the Run Tests link in the Test Impact View window. While I won't talk further about the test impact view, it's worth using in your TDD activities. OK so this iteration is complete now for the calculation of the cannonball trajectory.

Iteration 5 - Shoot, the Messenger:Shot!!!
Time for the real fun of the shoot method. As the next four requirements are very close, I am going to include them in this iteration. Normally we would break these up but to keep this tutorial as brief as possible we'll group them together. They are:

  • Target Distance is simply the distance of the Cannon to Target, and is created randomly by default but can be overridden;
  • Max distance for target is 20000 meters;
  • Base the algorithm for the calculation of the cannons trajectory upon the following C# code (distance and height is meters and velocity is meters per second):
    • distance = velocity * Math.Cos(angleInRadians) * time;
    • height = (velocity * Math.Sin(angleInRadians) * time) - (GRAVITY * Math.Pow(time, 2)) / 2;
  • A hit occurs if the cannon is within 50m of the target;

First, we need a test to set a distance for the target and the correct angle and velocity for a miss (yes we are going to test for a miss first). Actually, for this functionality we are going to add two tests: one to test a miss and one for a hit.

  • So lets add the tests:

[TestMethod]
public void TestCannonShootMiss()
{
    cannon.SetTarget(4000);
var shot = cannon.Shoot(45, 350);
Assert.IsTrue(shot.Item2 == "Missed cannonball landed at 12621 meters");
}
[TestMethod]
public void TestCannonShootHit()
{
    cannon.SetTarget(12621);
var shot = cannon.Shoot(45, 350);
Assert.IsTrue(shot.Item2 == "Hit");
}

  • This will not compile so we can right click SetTarget and select Generate Method Stub.
  • Run the tests and of course the last two tests fail
  • We need to some changes to make it succeed, add this private variable and readonly int to the class:

private int distanceOfTarget;
private readonly double GRAVITY = 9.8;

  • below the validation code replace
    return Tuple.Create(true, "Angle OK"); //Not going to do //the calculation just yet
    with:
    string message;
    bool hit;
    int distanceOfShot = CalculateDistanceOfCannonShot(angle, velocity);
    if (distanceOfShot == distanceOfTarget)
    {
        message = "Hit";
        hit = true;
    }
    else
    {
        message = String.Format("Missed cannonball landed at {0} meters", distanceOfShot);
        hit = false;
    }
    return Tuple.Create(hit, message);
  • and then we create another method

public int CalculateDistanceOfCannonShot(int angle, int velocity)
{
    int time = 0;
double height = 0;
double distance = 0;
double angleInRadians = (3.1415926536 / 180) * angle;
while (height >= 0)
    {
        time++;
        distance = velocity * Math.Cos(angleInRadians) * time;
        height = (velocity * Math.Sin(angleInRadians) * time) - (GRAVITY * Math.Pow(time, 2)) / 2;
    }
return (int)distance;
}

  • Now Compile and run the tests and they will fail - because we are throwing an exception in SetTarget so lets change SetTarget to :

public void SetTarget(int distanceOfTarget)
{
this.distanceOfTarget = distanceOfTarget;
}

  • Run the tests again and now they all pass GREEN. Time to refactor.
  • Lets add some code to the constructor of the cannon class to randomly set it

private Cannon()
{
//by default we setup a random target
Random r = new Random();
    SetTarget(r.Next(MAXDISTANCEOFTARGET));
}

  • and a constant for MAXDISTANCEOFTARGET

private readonly int MAXDISTANCEOFTARGET = 20000;

  • Make sure DistanceOfTarget is now a property:

public int DistanceOfTarget
{
get { return distanceOfTarget; }
set { distanceOfTarget = value; }
}

  • And now SetTarget can change to:

public void SetTarget(int distanceOfTarget)
{
    if (!distanceOfTarget.Between(0, MAXDISTANCEOFTARGET))
    {
throw new ApplicationException(String.Format("Target distance must be between 1 and {0} meters", MAXDISTANCEOFTARGET));
    }
this.distanceOfTarget = distanceOfTarget;
}

  • And we need to include the burst radius code in the Shoot method which will replace:

if (distanceOfShot == distanceOfTarget)

  • With

if (distanceOfShot.WithinRange(this.distanceOfTarget, BURSTRADIUS))

  • and a couple of important changes here
    • We are using an extension method to provide a number of additional functions to ints.
    • To add an extension method we follow the following steps:
      • Add a class to the console project
      • Call it ExtensionMethods.cs
      • Enter the following code:

using System;
namespace System
{
public static class ExtensionMethods
    {
public static bool Between(this int source, int min, int max)
        {
return (source >= min && source <= max);
        }
public static bool WithinRange(this int source, int target, int offset)
        {
return (target.Between(source - offset, source + offset));
        }
    }
}

    • We also need a BURSTRADIUS constant added to the class:

private readonly int BURSTRADIUS = 50;

The reason we use an extension method is because the Between and Within Range will be used often within the app. As we used the System namespace for these extension methods they will be provided always.
OK, So run the tests again and we find that they pass so time to move onto the next iteration
Iteration 6 - Counting Shots not Crows.
So the last piece of functionality to test is the Number of Shots so lets start with a simple test.

  • insert this after the last test.

[TestMethod]
public void TestCannonCountShots()
{
    cannon.SetTarget(12621);
var shot = cannon.Shoot(45, 350);
Assert.IsTrue(shot.Item2 == "Hit - 1 Shot(s)", "Number of shots:" + cannon.Shots);
}
This will not compile because Shots doesn't exist yet.

  • Right click on the Shots property and select Generate->Property
  • Run the tests again and you will see this fail so lets make some changes to Cannon including:
    • Change the property for Shots to:

public int Shots
{
get
    {
return shots;
    }
}

    • Add a field to the class

private int shots;

    • Initialise the variable in the constructor. It should now look like:

private Cannon()
{
//by default we setup a random target
Random r = new Random();
    SetTarget(r.Next((int)MAXDISTANCEOFTARGET));
}

    • Increment the shot count in the shoot method - insert this after the validation for the speed of light:
      shots ++;
    • Change the message of the hit to:
      message = String.Format("Hit - {0} Shot(s)", shots);
  • Run the tests again we see the following:
    clip_image014

This tells us the shot count is 3 not 1 (it also shows that the original test for a hit has to change to handle the new text) and the reason for this is the singleton pattern we are using. As we are only maintaining one instance of the object, that instance is actually being used for every Shoot that occurs during the run of tests. So we need to ensure every time we start a new game (ie. a new test) we reset the shot count. The easiest way is to introduce a Reset method where we can reset the shot count but also later on we can use this method for other things that need to be cleaned up/reset.

  • Add the following to Cannon.cs:

public void Reset()
{
    shots = 0;
}

  • The way we can use this in our tests is by using a method that is being called before every test. Add the following method to CannonAttackTest

[TestInitialize]
public void ResetCannonObject()
{
   cannon.Reset();
}

  • Let's change the original for test for the hit to:

[TestMethod]
public void TestCannonShootHit()
{
    cannon.SetTarget(12621);
var shot = cannon.Shoot(45, 350);
Assert.IsTrue(shot.Item2 == "Hit - 1 Shot(s)");
}

  • Run the tests CTRL-F5. They will all pass:
    clip_image015

and the cannon class is pretty much done. This is the end of the 6th Iteration and the Classes are complete. We are now going to write the code for CannonAttack that will call the classes from the UI.
Completing the Project
We can writethe Code in the Console UI to get the values from the user for the angle. This is important part because we haven't thought about UI till now, All the UI should be handled by the console. To do this:

  • Set the CannonAttack console project as the startup project
  • Add the following code to the CannonAttack.cs file

using System;
namespace CannonAttack
{
class CannonAttack
    {
private static readonly int MaxNumberOfShots = 50;
static void Main(string[] args)
        {
Console.WriteLine("Welcome to CannonAttack");
bool isStillPlaying = true;
while (isStillPlaying)
            {
bool isAHit = false;
Cannon cannon = Cannon.GetInstance();
while (!isAHit && cannon.Shots < MaxNumberOfShots)
                {
int angle;
int velocity;
Console.WriteLine(String.Format("Target is at {0} meters", cannon.DistanceOfTarget));
                    GetInputVariable(out angle, out velocity);
var shot = cannon.Shoot(angle, velocity);
                    isAHit = shot.Item1;
Console.WriteLine(shot.Item2);
                }
                isStillPlaying = GetIsPlayingAgain();
                cannon.Reset();
            }
Console.WriteLine("Thanks for playing Cannon Attack");
        }
    }
}
This is the core of the application and it should provide the main basis for the cannon attack application.
Below are the additional helper methods that are needed, so add them in underneath the main method:

private static bool GetIsPlayingAgain()
{
    bool isPlayingAgain = false;
bool validAnswer = false;
while (!validAnswer)
    {
Console.Write("Do you want to play again (y/n)?");
string playAgain = Console.ReadLine();
if (playAgain == "y" || playAgain == "Y")
        {
            isPlayingAgain = true;
            validAnswer = true;
        }
if (playAgain == "n" || playAgain == "N")
        {
            isPlayingAgain = false;
            validAnswer = true;
        }
    }
return isPlayingAgain;
}
private static void GetInputVariable(out int angle, out int velocity)
{
    string angleBuffer;
string velocityBuffer;
Console.Write(String.Format("Enter Angle ({0}-{1}):", Cannon.MINANGLE, Cannon.MAXANGLE));
    angleBuffer = Console.ReadLine();
if (!int.TryParse(angleBuffer, out angle))
    {
Console.WriteLine("Not a number, defaulting to 45");
        angle = 45;
    }
Console.Write("Enter Velocity (meters per second):");
    velocityBuffer = Console.ReadLine();
if (!int.TryParse(velocityBuffer, out velocity))
    {
Console.WriteLine("Not a number, defaulting to 100 meters per second");
        velocity = 100;
    }
}
Now you should be able to run the application and it should work displaying the output similar to what we defined on page 2 and should look like:

clip_image016
This is the End
That's it - your first TDD project is complete!!!. The next tutorial will introduce a number of new areas of functionality including:

  • Multiplayer; and
  • Mountains.

Any feedback you have would be appreciated as I'll update this tutorial as needed.
Additional Resources

Tuesday, May 18, 2010

Image Processing Lab in C#

Posted on/at 1:49 AM by Admin

· Download demo - 1025.2 KB

· Download source - 548.0 KB

clip_image001

Introduction

Image Processing Lab is a simple tool for image processing, which includes different filters and tools to analyze images available in the AForge.NET framework. It's easy to develop your own filters and to integrate them with the code or use the tools in your own application. The following filters are implemented in the AForge.NET framework and demonstrated in the application:

  • Color filters (grayscale, sepia, invert, rotate, channel extraction, channel replacing, channel filtering, color filtering, Euclidean color filtering);
  • HSL filters (linear correction, brightness, contrast, saturation, hue modifier, HSL filtering);
  • YCbCr filters (linear correction, YCbCr filtering, channel extraction/replacement);
  • Binarization filters (threshold, threshold with carry, ordered dithering, Bayer dithering, Floyd-Steinberg, Burkes, Jarvis-Judice-Ninke, Sierra, Stevenson-Arce, Stucki dithering methods);
  • Automatic binarization (simple image statistics);
  • Mathematical morphology filters (erosion, dilatation, opening, closing, hit & miss, thinning, thickening);
  • Convolution filters (mean, blur, sharpen, edges, Gaussian);
  • 2 Source filters (merge, intersect, add, subtract, difference, move towards, morph);
  • Edge detectors (homogeneity, difference, sobel, canny);
  • Blob counter, Connected components labeling;
  • Pixellate, Simple skeletonization, Jitter, Shrink, Oil painting;
  • Levels linear filter, gamma correction;
  • Median filter, Adaptive smoothing, Conservative smoothing;
  • Resize and Rotate;
  • Texture generators based on Perlin noise;
  • Texture filters (texturer, textured filtering, textured merging);
  • Fourier transformation (lowpass and hipass filters).

You can create (save and load) your own convolution filters or filters based on standard mathematical morphology operators. Colorized grid makes it very convenient to work with custom convolution filters.

A preview window allows you to view the results of changing filter parameters on the fly. You can scroll an image using the mouse in the preview area. All filters are applied only to the portion of the image currently viewed to speed up preview.

A PhotoShop-like histogram allows you to get information about mean, standard deviation, median, minimum and maximum values.

The program allows you to copy to or paste from clipboard, save and print images.

Using the Code

Most filters are designed to work with 24bpp RGB images or with grayscale images. In the case of grayscale images, we use PixelFormat.Format8bppIndexed with color palette of 256 entries. To guarantee that your image is in one of the formats, you can use the following code:

// load an image

System.Drawing.Bitmap image = (Bitmap) Bitmap.FromFile( fileName );

// format image

AForge.Imaging.Image.FormatImage( ref image );

It is easy to apply any filter to your image:

// load an image

System.Drawing.Bitmap image = (Bitmap) Bitmap.FromFile( fileName );

// create filter

AForge.Imaging.Filters.Median filter = new AForge.Imaging.Filters.Median( );

// apply filter

System.Drawing.Bitmap newImage = filter.Apply( image );

Suppose, you want to apply a series of filters to an image. The straight way to do it is to apply filters one after another, but it's not very likely in the case of 3 or more filters. All filters implement the IFilter interface, so it allows us to create a collection of filters and apply it at once to an image (besides, the collection will also save us from disposing routines on intermediate images):

// create filters sequence AForge.Imaging.Filters.FiltersSequence

filter = new AForge.Imaging.Filters.FiltersSequence( );

// add filters to the sequence

filter.Add( new AForge.Imaging.Filters.Sepia( ) );

filter.Add( new AForge.Imaging.Filters.RotateBilinear( 45) );

filter.Add( new AForge.Imaging.Filters.ResizeBilinear( 320, 240 ) );

filter.Add( new AForge.Imaging.Filters.Pixellate( 8 ) );

filter.Add( new AForge.Imaging.Filters.Jitter( 2 ) );

filter.Add( new AForge.Imaging.Filters.Blur( ) );

// apply the sequence to an image

System.Drawing.Bitmap newImage = filter.Apply( image );

It's easy to get such image statistics as mean, standard deviation, median, minimum and maximum values. It can be useful for image brightness/contrast regulation.

// get image statistics

AForge.Imaging.ImageStatistics statistics =

new AForge.Imaging.ImageStatistics( image );

// get the red histogram

AForge.Math.Histogram histogram = statistics.Red;

// get the values

double mean = histogram.Mean; // mean red value

double stddev = histogram.StdDev; // standard deviation of red values

int median = histogram.Median; // median red value

int min = histogram.Min; // min red value

int max = histogram.Max; // max value

// get 90% range around the median

AForge.IntRange range = histogram.GetRange( 0.9 );

Image statistics can be easily combined with filters. Suppose that the minimum value of red is 50 on the image and the maximum value is 200. So, we can normalize the contrast of the red channel:

// create levels filter

AForge.Imaging.Filters.LevelsLinear filter =

new AForge.Imaging.Filters.LevelsLinear( );

filter.InRed = new IntRange( histogram.Min, histogram.Max );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

Or we can normalize the contrast of each channel, getting only the 90% ranges from each channel:

// create levels filter

AForge.Imaging.Filters.LevelsLinear filter =

new AForge.Imaging.Filters.LevelsLinear( );

filter.InRed = statistics.Red.GetRange( 0.9 );

filter.InGreen = statistics.Green.GetRange( 0.9 );

filter.InBlue = statistics.Blue.GetRange( 0.9 );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

HSL Filters

Using HSL color space is more obvious for some sorts of filters. For example, it's not very clean, how to adjust saturation levels of an image using RGB color space. But it can be done easily, using HSL color space:

// create filter

AForge.Imaging.Filters.SaturationCorrection filter =

new AForge.Imaging.Filters.SaturationCorrection( 0.1 );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

clip_image002
Initial image

clip_image003
Saturation adjusted

Using HSL color space, we can modify the hue value of pixels. Setting all hue values to the same value will lead to an image in gradations of one color:

// create filter

AForge.Imaging.Filters.HueModifier filter =

new AForge.Imaging.Filters.HueModifier( 142 );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

It's possible to get much more interesting results using HSL filtering. For example, we can preserve only the specified range of hue values and desaturate all others out of the range. So, it will lead to a black and white image with only some regions colored.

// create filter

AForge.Imaging.Filters.HSLFiltering filter =

new AForge.Imaging.Filters.HSLFiltering( );

filter.Hue = new IntRange( 340, 20 );

filter.UpdateHue = false;

filter.UpdateLuminance = false;

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

clip_image004
Hue modified

clip_image005
HSL filtering

Mathematical Morphology Filters

There are many tasks that can be accomplished using mathematical morphology filters. For example, we can reduce noise on binary images using erosion, or we can separate some objects with the filter. Using dilatation, we can grow some parts of our interest on the image. One of the most interesting morphological operators is known as Hit & Miss. All other morphological operators can be expressed from the Hit & Miss operator. For example, we can use it to search for particular structures on the image:

// searching for vertical lines

short[,] vse = new short[3, 3] {

{ 0, 1, 0 },

{ 0, 1, 0 },

{ 0, 1, 0 }

};

AForge.Imaging.Filters.HitAndMiss vFilter =

new AForge.Imaging.Filters.HitAndMiss( vse );

System.Drawing.Bitmap vImage = vFilter.Apply( image );

// searching for horizontal lines

short[,] hse = new short[3, 3] {

{ 0, 0, 0 },

{ 1, 1, 1 },

{ 0, 0, 0 }

};

AForge.Imaging.Filters.HitAndMiss hFilter =

new AForge.Imaging.Filters.HitAndMiss( hse );

System.Drawing.Bitmap hImage = hFilter.Apply( image );

clip_image006
Original image

clip_image007
Searching for vertical lines

clip_image008
Searching for horizontal lines

Using a thickening operator, we can grow some parts of the image in the places we need. For example, the next sample will lead to thickening horizontal lines in the bottom direction:

// create filter

AForge.Imaging.Filters.FilterIterator filter =

new AForge.Imaging.Filters.FilterIterator(

new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 1, 1, 1 }, { -1, 0, -1 }, { -1, -1, -1 } },

HitAndMiss.Modes.Thinning ), 5 );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

clip_image006[1]
Original image

clip_image009
Thickened image

Using a thinning operator, you can remove some unnecessary parts of the image. For example, you can develop a skeletonization filter with appropriate structuring elements:

// create filter sequence

AForge.Imaging.Filters.FiltersSequence filterSequence =

new AForge.Imaging.Filters.FiltersSequence( );

// add 8 thinning filters with different structuring elements

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 0, 0, 0 }, { -1, 1, -1 }, { 1, 1, 1 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { -1, 0, 0 }, { 1, 1, 0 }, { -1, 1, -1 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 1, -1, 0 }, { 1, 1, 0 }, { 1, -1, 0 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { -1, 1, -1 }, { 1, 1, 0 }, { -1, 0, 0 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 1, 1, 1 }, { -1, 1, -1 }, { 0, 0, 0 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { -1, 1, -1 }, { 0, 1, 1 }, { 0, 0, -1 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add(new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 0, -1, 1 }, { 0, 1, 1 }, { 0, -1, 1 } },

HitAndMiss.Modes.Thinning ) );

filterSequence.Add( new AForge.Imaging.Filters.HitAndMiss(

new short [,] { { 0, 0, -1 }, { 0, 1, 1 }, { -1, 1, -1 } },

HitAndMiss.Modes.Thinning ) );

// create filter iterator for 10 iterations

AForge.Imaging.Filters.FilterIterator filter =

new AForge.Imaging.Filters.FilterIterator( filterSequence, 10 );

// apply the filter

System.Drawing.Bitmap newImage = filter.Apply( image );

clip_image010
Original image

clip_image011
Thinned image

Fourier Transformation

It is easy to perform a Fourier transformation, which is useful for image analysis and filtering with the library:

// create complex image from bitmap

AForge.Imaging.ComplexImage cimage =

AForge.Imaging.ComplexImage.FromBitmap( bitmap );

// perform forward Fourier transformation

cimage.ForwardFourierTransform( );

// get frequency view

System.Drawing.Bitmap img = cimage.ToBitmap( );

clip_image012

Lowpass and hipass filtering can be performed using the FrequencyFilter method of the ComplexImage class:

// lowpass filtering

cimage.FrequencyFilter( new Range( 0, 100 ) );

// perform backward Fourier transformation

cimage.BackwardFourierTransform( );

// get filtered image

System.Drawing.Bitmap img = cimage.ToBitmap( );

Blob Counter

Blob counter is a very useful feature and can be applied in many different applications. What does it do? It can count objects on a binary image and extract them. The idea comes from "Connected components labeling," a filter that colors each separate object with a different color. Let's look into a small sample:

// create filter

AForge.Imaging.Filters.ConnectedComponentsLabeling filter =

new AForge.Imaging.Filters.ConnectedComponentsLabeling( );

// apply filter

System.Drawing.Bitmap newImage = filter.Apply( image );

// objects count

System.Diagnostics.Debug.WriteLine( "Objects count: " +

filter.ObjectCount );

Here are two images: initial image and colored image. So, it looks like the filter is really able to count objects.

clip_image013

clip_image014

Here is another example of objects counting and retrieving their position and size:

// process an image

AForge.Imaging.BlobCounter blobCounter = new BlobCounter( image );

Rectangle[] rects = blobCounter.GetObjectRectangles( );

// objects count

System.Diagnostics.Debug.WriteLine( "Objects count: " + rects.Length );

// objects dimension

foreach ( Rectangle rc in rects )

{

System.Diagnostics.Debug.WriteLine(

string.Format("Position: ({0}, {1}), Size: {2} x {3}",

rc.Left, rc.Top, rc.Width, rc.Height ) );

}

It's possible to extract each object with the GetObjects method of BlobCounter:

// process an image

AForge.Imaging.BlobCounter blobCounter = new BlobCounter( image );

Blob[] blobs = blobCounter.GetObjects( image );

// process blobs

foreach ( Blob blob in blobs )

{

// ...

// blob.Location - location of the blob

// blob.Image - blob`s image

}

YCbCr Filtering

YCbCr filters are provided with similar functionality to RGB and HSL filters. The YCbCr linear correction filter performs as its analogues from other color spaces, but operates with the Y, Cb and Cr components respectively, providing us with additional convenient ways of color correction. The next small sample demonstrates the use of the YCbCr linear filter and the use of in-place filtering: the feature, which allows you to filter a source image instead of creating a new result image, is as follows:

// create filter

YCbCrLinear filter = new YCbCrLinear( );

filter.InCb = new DoubleRange( -0.276, 0.163 );

filter.InCr = new DoubleRange( -0.202, 0.500 );

// apply filter

filter.ApplyInPlace( image );

clip_image015

clip_image016

Perlin Noise Filters

Perlin noise has many applications and one of the most interesting of them is the creation of different effects, like marble, wood, clouds, etc. Application of such effects to images can be done in two steps. The first step is to generate effect textures and the second step is to apply the textures to the particular image. Texture generators are placed into the Texturesnamespace of the library, which contains generators for such effects as clouds, wood, marble, labyrinth and textile. All these texture generators implement the ITextureGeneratorinterface. For applying textures to images, there are three filters. The fist one, Texturer, is for texturing images. The second, TexturedFilter, allows application of any other filter to an image using the texture as a mask. The third, TexturedMerge, allows merging of two images using the texture as a mask.

// 1 - Marble effect

// create texture

ITextureGenerator generator = new MarbleTexture( );

float[,] texture = generator.Generate( image.Width, image.Height );

// create filter

IFilter filter1 = new Texturer( texture );

// apply filter

Bitmap newImage1 = filter1.Apply( image );

// 2 - Wood effect

// create filter

IFilter filter2 = new Texturer( new WoodTexture( ) );

// apply filter

Bitmap newImage2 = filter2.Apply( image );

// 3 - Textile effect

// create filter

IFilter filter3 = new Texturer( new TextileTexture( ) );

// apply filter

Bitmap newImage3 = filter3.Apply( image );

// 4 - Rusty effect

IFilter filter4 = new TexturedFilter( new CloudsTexture( ),

new Sepia( ) , new GrayscaleBT709( ) );

// apply filter

Bitmap newImage4 = filter4.Apply( image );

clip_image017

clip_image018

clip_image019

clip_image020

AForge.NET Framework

The Image Processing Lab application is based on the AForge.NET framework, which provides all the filters and image processing routines available in the application. To get more information about the framework, you may read the dedicated article on The Code Project or visit the project's home page, where you can get all the latest information about it, participate in a discussion group or submit issues or requests for enhancements.

Conclusion

I suppose the code may be interesting for someone who would like to start studying image processing or for filters/effects developers. As for me, I'll use the tool for my further research in computer vision. Besides, the library helped me very much in successfully finishing my bachelor work.

History

  • [08.03.2007] - Version 2.4.0
    • Application converted to .NET 2.0;
    • Integrated with AForge.NET framework.
  • [13.06.2006] - Version 2.3.0
    • In place filter interface introduced, which allows filter application on the source image;
    • Perlin noise texture generators (marble, wood, textile, labyrinth, clouds);
    • Texture filters (texturer, textured filtering, textured merging);
    • RGB to YCbCr and YCbCr to TGB converters;
    • YCbCr filters;
    • Image statistics for YCbCr;
    • Other minor changes (fix of Canny edge detector, Pixellate filter updated, morph filter).
  • [20.09.2005] - Version 2.2.0
    • Canny edge detector;
    • Oil painting, Conservative smoothing;
    • Simple image statistics threshold.
  • [20.08.2005] - Version 2.1.0
    • Blob counter, Connected components labeling;
    • Sobel edge detector;
    • Adaptive smoothing, Gaussian blur, Image cropping.
  • [12.07.2005] - Version 2.0.0
    • Homogeneity and Difference edge detectors;
    • Fourier transformation (lowpass and hipass filters);
    • AForge namespace;
    • Copy and Paste to clipboard;
    • Image saving and printing.
  • [20.06.2005] - Version 1.4.0
    • More morphological methods (hit & miss, thinning, thickening);
    • HSL filters;
    • Gamma correction, filter iterator, etc.
  • [29.03.2005] - Version 1.3.0
    • Resize and rotate;
    • Jitter, Shrink, more dithering methods;
    • MaskedFilter.
  • [20.03.2005] - Version 1.2.0
    • More filters;
    • Preview window;
    • Grid colorization for morphology and convolution custom filters;
    • Support for two source filters;
    • Toolbar.
  • [03.03.2005] - Version 1.0.0

URL": http://www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx?display=Print

Dynamic Type in C# 4.0

Posted on/at 1:29 AM by Admin

Dynamic is a new type introduced in c# 4.0.Dynamic types are declared with the dynamic keyword. The objects of type Dynamic are not type checked at compile time. It behaves like type Object in most cases .Object of any type can be assigned to a variable of Dynamic type .Variable of Dynamic type can get its value even from HTML Document Object Model (DOM) or COM API. If the code is not valid, errors are caught at run time not at compile time.

C# was until now a statically bound language. This means that if the compiler couldn't find the method for an object to bind to then it will throw compilation error.

We declare at compile-time the type to be dynamic, but at run-time we get a strongly typed object.

Dynamic objects expose members such as properties and methods at run time, instead of compile time. If you try to access members of a Dynamic type in visual studioclip_image001 IDE you will get the message "The operation will be resolved at runtime".

clip_image002

Difference between Object, Var and Dynamic type

If we execute the following code

dynamic dyn = 0;

object obj = 0;

var var = 0;

System.Console.WriteLine(dyn.GetType());

System.Console.WriteLine(obj.GetType());

System.Console.WriteLine(var.GetType());

We will get the runtime types of all the Object ,Dynamic and var variables as Sytem.Int32 .But the type of var variable is available at compile time as well.

But now if we add the following two statements the second statement will give compile time error  because the expression is type checked at compile time while the first statement compiles successfully because expressions of dynamic type are not type checked at compile time and the var type variable is assigned the appropriate datatype at compile time itself.

dyn = dyn + 1;

obj = obj + 1;

var = var + 1;

If we execute the below program

class Dynamic

{

static void Main(string[] args)

    {

dynamic dyn;

string str = "Dynamic type test.String";

StringBuilder sb = new StringBuilder();

        sb.Append("Dynamic type test.StringBuilder");

        dyn = str;

        DynamicFunction(dyn);//This will call the first function because at run time the dynamic type is of string type

        dyn = sb;

        DynamicFunction(dyn);////This will call the first function because at run time the dynamic type is of string builder type

Console.Read();

    }

public static void DynamicFunction(string s)

    {

Console.WriteLine(s);

    }

public static void DynamicFunction(StringBuilder sb)

    {

Console.WriteLine(sb.ToString());

    }

}

We will get the output as shown below:

clip_image003

To conclude Dynamic Type is a nice feature when it comes to interoperatibility and .NET usage with other Dynamic languages. However Dynamic type also makes it the responsibility of the developerclip_image001[1] for the correct usage of the calls.

URL: http://www.c-sharpcorner.com/UploadFile/ashish_2008/1157/

Sunday, October 25, 2009

Developing and Deploying Custom Web Parts for SharePoint Portal 2007

Posted on/at 5:09 AM by Admin

   

Overview and difference with SPS 2003:

Developing Web Part for SharePoint Portal 2007 is different as compared to developing for SPS 2003. Web Parts Developed in .Net 1.1 for SPS 2003 used the SharePoint.WebPartPages namespace, however the Web Part in ASP.Net 2.0 is found under theSystem.Web.UI.WebControls.WebParts.

Development of Web Part in VS 2005

To Get Started with creating Custom Web Part for MOSS 2007 in Microsoft Visual Studio 2005, Open the IDE and create a new C# project, Select Class Library as Project Type. Name It as NewWebPart.

clip_image001

Add a reference to the System.Web  from .Net components into the project. The System.Web dll contains the required namespace ofSystem.Web.UI.WebControls.WebParts .

clip_image002

In The Project explorer view rename the Class1.cs with NewWbPart.cs to be consistent with this example; this will result in renaming the Class name as well. With the help of “using” keyword include the namespaces as shown in the code example below. Derive / Extend the NewWebPart Class from the WebPart Class ( System.Web.UI.WebControls.WebParts.WebPart), and add the code as shown below. The CreateChildren Control is same as in .Net 1.1, that it would create and add controls to this Web Part Class,. In this case I have only added a WebControl.Calender Object. The RenderControl Method is an override for the WebPart Base Class and calls the RenderChildren Method, this causes the Children Controls to be rendered on the Particular HtmlTextWriter passed as a parameter to the method.


using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

namespace NewWepPart

{

    public class NewWebPart : WebPart

    {

        protected override void CreateChildControls()

        {

            Calendar cldr = new Calendar();

            cldr.Enabled = true;

            cldr.ShowGridLines = true;

            cldr.ShowTitle = true;

            cldr.EnableViewState = true;

      cldr.SelectedDate = DateTime.Now;

            Controls.Add(cldr);       �

        }

        public override void RenderControl(HtmlTextWriter writer)

        {

            RenderChildren(writer);

        }

    }

}


Build the project and on successful built you are ready to Deploy the Web Part to the Portal Site.

Deployment of Web Part:

In order to deploy a web part to a SharePoint portal 2007 site, we must have the URL of the site to which we want our web part needs to be deployed (displayed in fact). As it  is mentioned earlier that the Web Parts developed in .Net 2.0 environment does have a .CAB project , instead an assembly is created on build of project. Now there are two choices to deploy the assembly to the SharePoint portal directory.

  • Deploy the assembly to the Assembly Folder (GAC) (requires the assembly to be stron named).
  • Put the assembly to the bin folder of the portal directory.

For the sake of simplicity, the later choice is being demonstrated in this example.


Putting Assembly in Bin Folder:

The MOSS 2007 creates every portal in the inetpub\wwwroot\wss folder. The easiest way to find the bin folder from these folder hierarchies is to go from inetmgr console. Locate the appropriate portal (for which u want to deploy the web part), identified with the port number. Right click and have Properties. Under the Home Directory Tab, note the path in Local path text box. Verify if the bin folder exists in the specified path by opening it in browser. If the folder doesn’t exist then create one. Now copy the assembly form the project output folder and paste it in bin folder of portal.

clip_image004

However there is another work around for putting the assembly in to the portal’s bin folder again ad again each time the Web Part Project is built with changes.

Right click on the project name (NewWebPart) in the VS.Net 2005 IDE and click properties. Under  the Build page paste the same path copied from inetmgr console into the Output Path. As shown in figure below. This will result in the latest assembly automatically deployed to the bin folder every time the project is built.

clip_image006

Adding the Safe Control Entry:

Even though the assembly is present in the Portal’s Bin folder, there is another step required to make the Control (Web Part) assembly usable on the Portal Pages. Since the control will need to render on multiple machines in different browsers with as many user accounts as the organizations have. There is a need to declare the control as “safe”. To do so open the web.config file placed under the portal’s directory in the VS.Net 2005 IDE.

clip_image008

Then edit the file in the section of SafeControls, create a new SafeControl entry for our assembly as shown below. Save the file and close it.

<SafeControls>

.

.

.

<SafeControl Assembly="NewWebPart" Namespace="NewWebPart" TypeName="*" Safe="True" />

SafeControls>

Configuring Portal to use NewWebPart

Since now the web part have been written and deployed to the desired portal’s directory. The next task is to use the web part on the Portal’s Site. The Web Part Deployed to the portal can be placed on any site within that Portal. For convenience this NewWebPart is demonstrated to be placed on the home page of default Portal.

Open the portal site in the internet explorer; in this case http://oss1 is the URL for the default portal, ensuring that the current logged in user has the administrative rights on the portal site.

To begin with, the first step is to add the newly deployed web to the Portal’s web part gallery, since the portal is using the configuration databases to keep record of the contents of the portal, our newly created web part’s information doesn’t exist in the database. We need to add the web part to the Web Part Gallery before we can use it.

To do so, the following steps should be followed.

1. Click on the Site Actions button and then select Site Settings.

clip_image010

2. On the site settings page under Galleries column click on the Web Parts.

clip_image012

3. On the Web Part Gallery Page click on the New button, to add the new web part assembly to the gallery.

clip_image014

4. On the New Web Parts page locate the NewWebPart in the list, check the check box on the left and click on the Populate Gallerybutton the top of the page. This will result in the Web Part entry creation in the Web Part Gallery list, and hence it can be used from now on from the gallery. It can be notices easily that the Web Parts developed form the new Frame work of 2.0 have an extension of .webpartafter their names. Whereas in earlier versions, it was a .dwp file. Both the .webpart and .dwp files are the XML definition of the Web Part.

clip_image016

5. Until this step the web part is ready to be used on the site by selecting it from Web Part Gallery. Click on the Site Actions button on the page and then select Edit Page, this will modify the appearance of the page to enable the edit view. In this view Web Part Zones are highlighted so that a user can add a web part to the zone, Click on the Add a Web Part button in the left zone to add the Web Part.

clip_image018

6. Select the NewWebPart from the web part list . it is found under the Misc section and then click on�Advanced Web Part gallery and options.

clip_image020

7. In the�Add Web Part Pane at right , select Home  Gallery and then drag the NewWebPart from the pane into the Web Part Zone.

clip_image021

8. Click on the Exit Edit Mode link on the page and the site will return to the view mode.

clip_image022

 
   

About Me

Developers house is a blog for posting technical articles in different technology like Microsft, Java, Oracle ..etc Microsoft technology includes c#,VB.net,ASP.net,Ajax,SilverLight,TFS,VS.NET 2003,2005,2008,2010 , SQL Server 2000, 2005 , Expression Blend , ...etc I hope it is helpful for all of you and if you are interested to post articles on it, only send me at ahmad.eed@gmail.com