January 2005 - Posts
The Enterprise Library for .Net 1.1, MSDN Patterns & Practices' new library that unifies a number of Application Blocks and that implements a shared Provider-based architecture, is available for free download here. Get it while it's hot!
Update: Jelle Druyts will be talking about the Enterprise Library at the Lightning Talks session on Tuesday evening!
On Tuesday, I'll be presenting 2 "Lightning Talks" at the Developer & ITPro Days event organized by Microsoft Belgium: "5 Ways to Improve your Unit Testing" and "How to make Session state strongly-typed and early-bound".
Other topics that are presented that evening (after 5 PM) include "Generating WordML with XSLT" by Wim Verhaeghen and "5 Ways to Secure your Web Applications" by Bart De Smet, among others. See also Bernard Vander Beken's site http://jawn.net/talks/ for details.
See you there?
Remember the post on Fun With Interfaces? Let's take this a step further...
The model from last time was the following:

ICouple inherits from IAlice and IBob; if you instantiate Carol, who implements IAlice and IBob, you can call the methods on both IAlice and IBob, but Carol does not automagically implement ICouple. However, if Carol was defined to implement ICouple, you could cast her to IAlice and to IBob and that would work:
ICouple carolOne = new Carol();
string carolA = carolOne.AliceSays();
string carolB = carolOne.BobSays();
carolA = ((IAlice) carolOne).AliceSays();
carolB = ((IBob) carolOne).BobSays();
This works, but interestingly enough, at development time IntelliSense can't really figure it out -- it does display AliceSays() in the list of methods, but not BobSays(). But it does compile and run just fine.
Now, let's make the model a bit more complex:

We still have the same interfaces, but now we have a new type called OddCouple which implements both ICouple and IBob.
OddCouple can implement both these methods:
public
virtual string AliceSays()
{
return "Alice";
}
public virtual string BobSays()
{
return "Bob";
}
Question 1: What will this do at compiletime, and at runtime?
The following code is expected to work, and in fact it does:
ICouple theTwo = new OddCouple();
string whatBobSays = theTwo.BobSays();
string whatAliceSays = theTwo.AliceSays();
The code in this example also works, as you'd expect:
IBob mrBob = new OddCouple();
whatBobSays = mrBob.BobSays();
After all, OddCouple implements IBob explicitly. Now, what happens when you try the following?
IAlice mrsAlice = new OddCouple();
whatAliceSays = mrsAlice.AliceSays();
Question 2: To make matters even more complicated, we have another type called OdderStill which inherits from OddCouple and explicitly declares that it implements IAlice. What will this do at compiletime, and at runtime?
Question 3: Do I have too much time on my hands?
When working on a large application, I had to write some utility functions to convert integers into corresponding enum values. Say you had an enum like the following:
Public
Enum TrafficLight As Integer
None = 0
Red = 1
Yellow = 2
Green = 3
End Enum
Then you could have a function to convert integers to TrafficLights such as
Public Function TrafficLightFromInt32(value As Integer) As TrafficLight
At first, I tried solving it by using the following technique:
Public Function TrafficLightFromInt32(value As Integer) As TrafficLight
Dim result As TrafficLight
result = DirectCast(System.ComponentModel.TypeDescriptor.GetConverter(GetType(TrafficLight)).ConvertFrom(value), TrafficLight)
Return result
End Function
But that didn't work, because EnumConverter can't convert from a System.Int32.
The solution was in fact much simpler:
Private Function TrafficLightFromInteger(ByVal value As Integer) As TrafficLight
Dim name As String = [Enum].GetName(GetType(TrafficLight), value)
Dim result As TrafficLight = DirectCast([Enum].Parse(GetType(TrafficLight), name), TrafficLight)
Return result
End Function
And voilà...
Update: I am deeply humbled by the much simpler solutions that Wes and Wesner have offered in the Feedback to this posting. There's no need to parse and cast, a simple CType() -- in the case of Visual Basic.Net -- does the trick. I have an aversion for CType() but in this case it's totally unjustified. Thanks for pointing that out!
Update 2: However, there is a caveat to using CType(). That is, enums are by default stored as Integer. You can then CType any integer to the enum, even integers that don't represent legal values. To take the example above, you can do CType(5, TrafficLight) and it wouldn't even throw an exception at runtime. You can solve that by checking for valid enum values before using them, as in the following example:
Public Sub UpdateTrafficLight(value As TrafficLight)
If Not [Enum].IsDefined(GetType(TrafficLight), value ) Then
Throw New ArgumentException("UpdateTrafficLight: value is invalid.")
End If
...
End Sub
I had hoped we'd see the bits of Visual Studio 2005 "Whidbey" by the January timeframe, nicely in time for the Developer & IT Pro Days in Belgium on 1 and 2 February, or the VSLive! conference in San Francisco. Unfortunately, it appears that Microsoft has its eyes on a March 31 release date for the new bits, which will be fully supported -- meaning software companies can release production software built with it and enjoy Redmond's support.
Beta 2 will have a slightly different API from Beta 1, ASP.NET will feature a different directory structure than Beta 1 and especially System.Xml will receive a major overhaul... So if you're developing with Beta 1 or the December CTP, keep in mind that after March 31 you'll need to make some changes to your code.
Currently, the development team is doing a security push on the Beta 2 bits, meaning that when the code is released, it will be considered secure... and probably the bug-freest development environment Microsoft has ever released. I wish it was already here!
Last Friday's Belgian Geek Dinner was really great. There were 19 of us and we all had a really great time, mingling and talking and of course eating and drinking with gusto. The Attila is a really great place for this type of get-togethers. Patrick Tisseghem suggested that we follow this up in a couple of months with a Geek Party. Sounds like a plan, Patrick!
Update: David Boschmans has posted some pictures on his MSN Space... Cool slideshow!
Remember my previous post about how Visual Studio.Net ruined my day? The story didn't end there...
Because the next day, the problem came back. Everyone on the team was suffering from it, it was spreading like wildfire. That's the disadvantage of source code control I guess :-)
But after a lot of swearing, sweating, bleeding, and a lot of other unpleasant things, we found the actual cause of the problem -- never mind the fact that, in the case of a Parser Error with Global.asax.vb, you could solve the problem by adding a space to the source code, saving, compiling and repeating...
The cause of the Parser Error which kept cropping up, everywhere in the project, was inconsistent use of namespace casing (in my defense, I joined this project very late and the codebase didn't use the proper naming conventions.) That is, a number of .aspx files would contain an "Inherits" attribute which contained proper Pascal casing for the namespace, whereas the project settings would not:
<%@Page Language="vb" ... Inherits="Company.Project.UI.Web.MyPage.aspx.vb" ... %>
and
project settings' Default Namespace: Company.PROJECT.UI.Web
This inconsistency caused Visual Basic.Net to totally lose it and go nuts on us. The solution was to have everyone check in their code, and let an appointed "volunteer" do a complete Checkout, find/replace all occurrences of the capitalized word by the Pascal-cased word, update the necessary file and directory names, delete the IIS Virtual Directory and create a new one, recompile and check everything back in. The Cleanup utility was a tremendous help here (of course :-)).
So try this first before you strangle anyone! (I sincerely apologize to my victim's family and friends. I feel their pain...)
Let's have some fun with interfaces. This posting was
inspired by a recent call for help from a colleague.
Say you have two basic interfaces, IAlice and IBob, as in
the following code:
using
System;
namespace
FunWithInterfaces
{
public interface IAlice
{
string AliceSays();
}
}
and
using
System;
namespace
FunWithInterfaces
{
public interface IBob
{
string BobSays();
}
}
And say you have a third interface, ICouple, which just
inherits from these two:
using
System;
namespace
FunWithInterfaces
{
public interface ICouple : IAlice, IBob
{
}
}
Now, so far, so good. What if you had a class, Carol --
who speaks for both Alice and Bob -- who implements IAlice and IBob, like
so:
using
System;
namespace
FunWithInterfaces
{
/// <summary>
/// Carol speaks for both Alice and Bob --
/// but does she speak for the
couple?
/// </summary>
public
class Carol : IAlice, IBob
{
public string AliceSays()
{
return "Bob, come
home!";
} // AliceSays
public
string BobSays()
{
return "I can't, watching
sports!";
}
}
}
Does Carol also speak for the couple? That
is, is she automatically seen by the .Net Framework as implementing ICouple?
What happens when you do this?
ICouple somebody = (ICouple)
new Carol();
Try to find the answer before trying it out :-)
Microsoft will officially release the Enterprise Library, a reworked and integrated combination of a number of Application Blocks, on January 28. Enterprise Library (a.k.a. EntLib) will contain the Application Blocks for Data Access, Exception Handling, Caching, Configuration, Logging & Instrumentation, Security and Cryptography. Later releases will probably include other Application Blocks as well, for instance the User Interface Process Application Block (currently at version 2).
The great thing about EntLib is not just that these convenient Application Blocks come in a single download, but also that they are integrated better and that they all use a provider model for extensibility. Operators and developers can configure the library using an MMC-based GUI, and you can add your own blocks and MMC modules.
New projects will definitely benefit enormously from using EntLib, shortening development cycles with the pre-built, pre-tested, highly configurable library. Eight more days...
Argh, today I ran into problems with Visual Studio.Net
2003, and they took me almost all day to solve. Sh** happens I guess.
First, I tried to compile on my system, but Visual
Studio.Net kept complaining that he couldn't open the Web project. I tried all
tricks that I could think of, including emptying the directory in C:\InetPub\wwwroot, and nothing worked. Then just to
make sure the problem was related to Visual SourceSafe -- the team I'm working
with is using this terrible source code control system, I'm afraid --, I cleaned
up all links with VSS and tried to open the Solution, and that worked. So VSS
was the culprit. For that problem at least.
I fixed the issues by:
- completely removing the source code from my hard
disk,
- clearing the Visual Studio.Net Web Cache,
- removing the Virtual Directory in
IIS, and
- opening the Solution using File / Source Control / Open
from Source Control.
Then I could open the Solution just fine and
compile...
Only to bump into Problem #2.
Whenever I built and ran the Web site, I got a "Parser
Error: Could not load type <xxx>".
Strange. Looked at the code, it was fine. Looked at the
reference in the ASPX file, it was fine.
Rebuilt. Same problem.
Cleaned the Web Cache again. Same problem.
Reset IIS. Yep, same thing.
Rebooted the darn-diddly-arn PC. No
change.
I once read that, after all else has failed, you should
read the manual. So I looked up this error on MSDN and
found that you "just have to build" the project... Which is exactly what I was
doing. To make sure, I opened the generated DLL with Reflector and surely, the code
was fine.
OK, so after rebuilding and cleaning caches and removing
bin and obj and so forth for about 20 times, I was ready to kill someone. I
strangled the first colleague who happened to enter my office, then I felt much
better and continued.
Finally, I:
- rebooted the PC,
- removed the virtual directory from IIS,
- removed all source code related to the project from the
hard disk,
- cleared th