Plunging into .NET Development

Weblog Pieter Gheysens
Microsoft .NET Development - C# - Enterprise Library - Visual Studio 2005 Team System - Compuware DevPartner - ...
 


Wednesday, April 27

Controlling Windows SystemTime on local machine

For implementing multiple unit-test scenarios, I had to be able to adjust the local Windows SystemTime because some of the methods in our application behave differently according to the local SystemTime.

A colleague of me find out that we had to make use of the API-call "SetSystemTime" (library kernel32.dll) to programmatically set the local SystemTime. Because all computers on the network are synchronized automatically by a network time server, we had also to be able to stop (and start) the local "Windows Time" Service in our code. Otherwise it would be possible that during the unit-tests the client might have been resynchronized with the network time server. The purpose of the Windows Time Service is to ensure that all computers in an organization use a common time.



I created a little test-project to work this out ...



Basically, the following steps are executed :
  1. Display current SystemTime
  2. Stop "Windows Time" Service
  3. Set new SystemTime (January 1, 2006, 00:00)
  4. Display current SystemTime
  5. Start "Windows Time" Service
  6. Force resync "Windows Time" Service
  7. Display current SystemTime
Here are some code-snippets (formatting of code is best viewed on my blog) of how these steps are performed :
  • Stop "Windows Time" Service

            private void stopWindowsTimeService()

            {

                //Stop Windows Time

                localProcess.StartInfo.FileName = "net";

                //Service to stop is "W32Time"

                localProcess.StartInfo.Arguments = "stop W32Time";

                localProcess.Start();

                //Wait for process to exit

                localProcess.WaitForExit();

     

                //Capture output in streamreader and sent it to screen

                streamReader = localProcess.StandardOutput;

                this.txtOutput.Text += streamReader.ReadToEnd();

     

                this.Refresh();

            }


    In the constructor of my Form I created a new process and I've set some properties for this process.

                //create new System.Diagnostics.Process

                localProcess = new Process();

                //do not show command-window

                localProcess.StartInfo.CreateNoWindow = true;

                //Redirect output to capture output with streamreader

                localProcess.StartInfo.UseShellExecute = false;

                localProcess.StartInfo.RedirectStandardOutput = true;



  • Set new SystemTime

            [DllImport("kernel32.dll")]

            private static extern bool SetSystemTime(ref SystemTime systemTime);


    Use namespace System.RunTime.InteropServices for DllImport-attribute. This will indicate that the method is exposed by an unmanaged dynamic-link library (kernel32.dll) as a static entry point. You will also need the SystemTime structure to pass the new SystemTime by reference. The new SystemTime will be set to January 1, 2006 00:00.

            private struct SystemTime

            {

                public short Year;

                public short Month;

                public short DayOfWeek;

                public short Day;

                public short Hour;

                public short Minute;

                public short Second;

                public short Milliseconds;

            }


                //set new SystemDateTime

                DateTime tempDateTime = new DateTime(2006, 1, 1, 0, 0, 0).ToUniversalTime();

                SystemTime systemTime = new SystemTime();

     

                systemTime.Year = Convert.ToInt16(tempDateTime.Year);

                systemTime.Month = Convert.ToInt16(tempDateTime.Month);

                systemTime.Day = Convert.ToInt16(tempDateTime.Day);

                systemTime.Hour = Convert.ToInt16(tempDateTime.Hour);

                systemTime.Minute = Convert.ToInt16(tempDateTime.Minute);

                systemTime.Second = Convert.ToInt16(tempDateTime.Second);

     

                //set new dateTime

                SetSystemTime(ref systemTime);


    Note that the method-call expects a DateTime in UTC (coordinated universal time).

  • Start "Windows Time" Service and force resync

            private void startWindowsTimeService()

            {

                //start Windows Time Process

                localProcess.StartInfo.FileName = "net";

                //Service to start is "W32Time"

                localProcess.StartInfo.Arguments = "start W32Time";

                localProcess.Start();

                //Wait for process to exit

                localProcess.WaitForExit();

     

                //Capture output in streamreader and sent it to screen

                streamReader = localProcess.StandardOutput;

                this.txtOutput.Text += streamReader.ReadToEnd();

     

                this.Refresh();

     

                //resync Windows Time

                localProcess.StartInfo.FileName = "w32tm";

                localProcess.StartInfo.Arguments = @" /resync";

                localProcess.Start();

                localProcess.WaitForExit();

     

                //Capture output in streamreader and sent it to screen

                streamReader = localProcess.StandardOutput;

                this.txtOutput.Text += streamReader.ReadToEnd();

     

                this.Refresh();

            }


    The resync-option tells the (local) computer that it should resynchronize its clock as soon as possible. If no computer is specified, the local computer will resynchronize. w32tm.exe is the executable to display/manage settings of the Windows Time Service.

Note that no error-handling has been added in the code.

I noticed another thing while working on this project. If you have set the local SystemTime to a date in the future and you've build a solution/project on this "future" date, then you should force a rebuild of your solution/project when returning to the current SystemTime because otherwise Visual studio .NET 2003 will make use of the latest dlls (those that have been built in the "future"). I took me a while to see this : I was sure that I've changed the source code, but nothing was changed while running the app ... Grrr. Working on a future date can also make your Outlook "reminders" pop-up or warn you that your password will expire and so on. Be sure to resync your local SystemTime if you want to stay out of trouble!

Monday, April 25

NUnit-bug TestFixtureSetUp / TestFixtureTearDown ??

Currently I'm using version 2.2 of NUnit for unit-testing.

The two attributes [TestFixtureSetUp] and [TestFixtureTearDown] are used inside a TestFixture to provide a single set of functions that are performed once (TestFixtureSetUp) prior to executing any of the tests in the fixture and once after (TestFixtureTearDown) all tests are completed. A TestFixture can have only one TestFixtureSetUp method and only one TestFixtureTearDown method.

Today I noticed that this is not entirely correct when selecting individual unit-tests to run. I created a small test-project to be sure ...

using System;

 

using NUnit.Framework;

 

namespace UnitTests

{

    [TestFixture]

    public class MyTests

    {

        private int x = 5;

        private int y = 2;

 

        [TestFixtureSetUp]

        public void GeneralSetUp()

        {

            Console.WriteLine("TestFixtureSetup");

        }

 

        [TestFixtureTearDown]

        public void GeneralTearDown()

        {

            Console.WriteLine("TestFixtureTearDown");

        }

 

        [SetUp]

        public void TestMethodSetUp()

        {

            Console.WriteLine("TestMethodSetup");

        }

 

        [TearDown]

        public void TestMethodTearDown()

        {

            Console.WriteLine("TestMethodTearDown");

        }

 

        [Test]

        public void TestAdd()

        {

            Console.WriteLine("Add");

            Assert.AreEqual(7, x+y);

        }

 

        [Test]

        public void TestSubtract()

        {

            Console.WriteLine("Subtract");

            Assert.AreEqual(3, x-y);

        }

    }

}





After selecting and running the two tests (TestAdd and TestSubtract) together in the NUnit-GUI, I got the result above where you can see in the output that the TestFixtureSetup and TestFixtureTearDown methods were executed twice (once for each test) instead of once.

When the entire class is selected for unit-testing, then it works fine and those methods are only executed once while the TestMethodSetUp and TestMethodTearDown methods are executed for each individual test-method.



In my opinion, all unit-tests selected by a checkbox have to be considered as a whole and therefore the "TestFixture" methods may only be called once ... or do I miss something here?

Monday, April 18

Importance of IntelliSense

Today, I noticed that IntelliSense suddenly stopped working properly in Visual Studio 2003. Very weird because I didn't do anything exotic that could stop it from working in my IDE. When I reviewed the options for my IDE-settings, I found out that "Auto list members" was indeed unchecked! Till now I still have no explanation for this behavior, but at least now it works again ...



I now also realize how dependent I've become (and surely many others) from using IntelliSense. Imagine that from tomorrow onwards, you couldn't make use of it anymore ... Yes, that would be very frustrating and your overall productivity would certainly decrease.

In Visual Studio 2005, IntelliSense will be even more important for productiviy because it will provide more context-sensitive filtered completion lists and you will be able to use IntelliSense Code Snippets for simplifying the amount of manual code you need to type by providing templates for common code-snippets.

Saturday, April 16

System.Web.Mail

The .NET namespace used to send email in .NET applications (web-applications and Windows Forms applications) is System.Web.Mail. This namespace contains three classes :
  • MailMessage
    Provides properties and methods for constructing an e-mail message.
  • MailAttachment
    Provides properties and methods for constructing an e-mail attachment.
  • SmtpMail
    Provides properties and methods for sending messages.
Constructing an e-mail message is very simple :

        private void sendMail()

        {

            //Create MailMessage-object

            MailMessage mailMessage = new MailMessage();

 

            //Set sender and receiver(s)

            mailMessage.From = "test@test.com";

            mailMessage.To = "FirstName.LastName@gmail.com";

 

            //mail-options

            mailMessage.Priority = MailPriority.Low;

            mailMessage.BodyFormat = MailFormat.Html;

 

            //Set subject and body

            mailMessage.Subject = "testmail";

            mailMessage.Body = "<b>Hello World</b>";

 

            //Add attachment to message

            MailAttachment attachment = new MailAttachment(@"c:\mailAttachment.doc");

            mailMessage.Attachments.Add(attachment);

 

            //Set SMTP-Server : name or IP-address

            SmtpMail.SmtpServer = "localhost";

 

            //Send Mail

            SmtpMail.Send(mailMessage);

        }



The first time I tried this to send an e-mail on my machine (localhost), I was confronted with the following error : Could not access 'CDO.Message' ojbect ...



After some googling, I found out that I had to change the "relay restrictions" on my Virtual SMTP Server. By default, the radio-button "Only the list below" is selected and you must add your ip-address to the list or you must select "All except the list below" to be able to send e-mail on your local machine.



Behind the scenes, the Collaboration Data Objects message component (CDOSYS : CDO.Message) is used for sending the e-mail messages. The cdosys.dll is installed by default on Windows 2003 and on Windows XP. So, System.Web.Mail is not a full .NET native implementation of the SMTP protocol ...

I remember that in the past (Windows NT 4) we had to use the cdonts.dll and this dll was only installed by the NT4 Option Pack or with the Personal Webserver (PWS). The mail message is delivered either through the SMTP mail service built into Windows or through an arbitrary SMTP server.

Out of curiosity, I used Reflector to see how the Send-method (SmtpMail class) was implemented and I was surprised to see that the cdonts.dll is still used to send e-mail messages, but only if your OS-version is smaller than or equals 4 (NT). If you look a little bit closer at the SmtpMail class, you can find the helper-classes for CdoNts and CdoSys. CdoNts creates a "CDONTS.NewMail" object and CdoSys creates a "CDO.Message" object.


Tuesday, April 12

Catching up ...

I haven't been active in blogging the last weeks, but that's just the beauty of blogging. You can blog at your own pace ;-).

Some interesting links:
  • ASP.NET 2.0 QuickStart Tutorial
    The ASP.NET QuickStart is a series of ASP.NET samples and supporting commentary designed to quickly acquaint developers with the syntax, architecture, and power of the ASP.NET Web programming framework. The QuickStart samples are designed to be short, easy-to-understand illustrations of ASP.NET features. By the time you finish reading this tutorial, you will be familiar with the broad range of the new features in ASP.NET 2.0, as well as the features that were supported in earlier versions.
  • VS 2005 Product Line-up : A Picture Says 1,000 Words
  • Microsoft Certified Architect Program [Via Jose Luis Manners]
    Microsoft plans to introduce a board-level certification, called the Microsoft Certified Architect Program, designed to "identify architectural expertise
  • Visual C# and Windows Forms On Tour
    Take this unique chance and participate in this one day, free-of-charge event on the latest version of Microsoft's powerful integrated development environment. Get to know its promising new features and profit from the exclusive know-how of specialists.
  • TechEd 2005 @ A'dam [5-8 July 2005]
    Microsoft's flagship European technical education conference for developers and IT professionals focusing on current and soon-to-be launched technologies.
  • The Beta Experience
    Countdown to Visual Studio 2005 Beta 2 [April 25, 2005].
  • Microsoft's SP2 gets pushy
    Microsoft is disabling its software tool that prevented Windows XP Service Pack 2 from automatically downloading itself onto business computers.

Monday, April 4

Check out your Gmail-account

Don't be surprised if you are only using a (very) small percentage of your storage-capacity. Google has just doubled your storage-capacity from 1 Giga-byte to 2 Giga-byte!! Enjoy!!

Update : Actually they're planning to go beyond 2 Giga-byte ...

Storage is an important part of email, but that doesn't mean you should have to worry about it. To celebrate our one-year birthday, we're giving everyone one more gigabyte. But why stop the party there? Our plan is to continue growing your storage beyond 2GBs by giving you more space as we are able. We know that email will only become more important in people's lives, and we want Gmail to keep up with our users and their needs. From Gmail, you can expect more.

G stands definitely for growth !! Hotmail? What are you waiting for?

Sunday, April 3

Time Management

The last weeks/months have really been hectic. A lot of "after hours" work to do and also my preparation for the Paris Marathon took a lot of time. Well, I now can say already that I won't reach the finish-line next Sunday because I injured myself during an indoor soccer game yesterday-afternoon (Yeah, quite stupid!). This is really frustrating because I wasn't planning to play, but because of a lack of available players I did show up to play. Wrong decision apparently ... Damn, I feel bad because I hate to give up! Ok, I wasn't prepared 100% for the marathon because I skipped a lot of training-runs, but the last weeks I did run my kilometers and my confidence to pass the finish-line was rising. The marathon-weekend will now be replaced by a simple sightseeing-trip to Paris (my girlfriend will be delighted). I will focus now on the 20km of Brussels ...

Next time I should follow a course Time Management to better prepare for such an event. For the moment the days are too short to execute what I want to do in 24 hours. Hopefully the "workload" will decrease a little bit in the future.

I still haven't finished my book on Test-Driven Development that I bought months ago and I actually can't wait to start reading some chapters of Code Complete (2nd edition). The thing is : the more you get to know about .NET by practice or by reading, the more you realize that there's still a lot interesting stuff to discover/learn. I think you know what I mean! Self-study and exploration/examination of new things is something what an ambitious developer will always have to keep in mind to move forward, but it's not always straightforward to plan those things in your free time.