sharing about .NET and technology RSS 2.0
 Tuesday, November 06, 2007

I has been a while that I released a new version of ComponentDropper and I am going to release a new update very soon. I received positive feedback, and I am planning to add some new features and certainly to provide an installer for the add-in. Please leave a comment if you have any suggestions about ComponentDropper. 

Tuesday, November 06, 2007 3:10:31 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 | 
 Wednesday, July 11, 2007

A new version of SyntaxColor4Writer has been released, version 0.24. It has been updated with the newest release of Windows Live Writer Beta 2 and CodeHighlighter 4.0.0048 from Actipro. There are also some minor changes in the layout of the sidebar.

SyntaxColor4Writer024

Please leave a comment to let me know if there are any issues and/or feedback!

Wednesday, July 11, 2007 12:44:02 AM (Romance Standard Time, UTC+01:00)  #    Comments [1] -

 Thursday, January 25, 2007

In some enterprise applications you need to show geographical data such as countries and postcodes. Most of the time you need it for a registration page, where the user need to fill in the country and postcode/area.

Geonames is a free geographical database that contains over 8 million geographical names and it can be accessed through a number of webservices. For example the url http://ws.geonames.org/countryInfo? gives an xml with all countries, whereas the following request http://ws.geonames.org/postalCodeSearch?placename=be gives us all postcodes for a particular country (e.g. Belgium).

Most likely you need two dropdown lists, one for countries and one for postcodes, where the postcode dropdown is dependent from the country dropdown list. This is a very good example to introduce AJAX by using the CascadingDropdown that is included in ASP.NET AJAX.

To implement this functionality we need to implement two methods on a webservice, namely GetCountries and GetPostalCodesByCountry. The GetCountries simply returns all countries sorted by name and looks like this:

GeonamesService.asmx.cs - Copy Code
[WebMethod] public CascadingDropDownNameValue[] GetCountries() { List<CascadingDropDownNameValue> list = new List<CascadingDropDownNameValue>(); CountryItemCollection countries = IStaySharp.Geonames.GeonamesService.GetAllCountries(); for (int i = 0; i < countries.Countries.Length; i++) { list.Add(new CascadingDropDownNameValue( countries.Countries[i].CountryName, countries.Countries[i].CountryCode)); } list.Sort(CompareCascadingDropDownNameValueByName); return list.ToArray(); }

Note that the list need to be converted to an array of CascadingDropDownNameValue objects. Note that we also sort the list by implementing a delegate named CompareCascadingDropDownNameValueByName.

GeonamesService.asmx.cs - Copy Code
private static int CompareCascadingDropDownNameValueByName(CascadingDropDownNameValue x, CascadingDropDownNameValue y) { if (x == null && y == null) return 0; else if (x == null && y != null) return -1; else if (x != null && y == null) return 1; else return x.name.CompareTo(y.name); }

The other webservice method, called GetPostalCodesByCountry, need to retrieve all postcodes for a particular country. The signature of the method is very strict. The parameter names must be named 'knownCategoryValues' and 'category', otherwise it will fail!

GeonamesService.asmx.cs - Copy Code
[WebMethod] public CascadingDropDownNameValue[] GetPostalCodesByCountry(string knownCategoryValues, string category) { List<CascadingDropDownNameValue> list = new List<CascadingDropDownNameValue>(); StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues); if (kv.ContainsKey("Country")) { string countryName = kv["Country"]; PostalCodeItemCollection postalCodes = IStaySharp.Geonames.GeonamesService.GetPostalCodes(countryName); for (int i = 0; i < postalCodes.PostalCodes.Length; i++) { list.Add(new CascadingDropDownNameValue( string.Format("{0} ({1})", postalCodes.PostalCodes[i].PostalCode, postalCodes.PostalCodes[i].Name), postalCodes.PostalCodes[i].PostalCode)); } } list.Sort(CompareCascadingDropDownNameValueByName); return list.ToArray(); }

In order to complete the webservice, the attribute ScriptService (line 3) need to be included so that a client javascript proxy can be generated. You can test this by calling your webservice like this http://localhost:9999/GeonamesService.asmx/js.

GeonamesService.asmx.cs - Copy Code
1 [WebService(Namespace = "http://tempuri.org/")] 2 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 3 [System.Web.Script.Services.ScriptService()] 4 public class GeonamesService : System.Web.Services.WebService 5 { 6 ... 7 }

Finally we only need to add two CascadingDropDown controls on our aspx page with the following settings:

Default.aspx - Copy Code
<asp:ScriptManager ID="scriptManager" runat="server" /> <asp:DropDownList ID="countriesDropDown" runat="server"/> <ajaxToolkit:CascadingDropDown ID="countriesCascadingDropDown" TargetControlID="countriesDropDown" Category="Country" PromptText="Please select a country" LoadingText="[Loading countries...]" ServicePath="/GeonamesService.asmx" ServiceMethod="GetCountries" runat="server"/> <br/><br/> <asp:DropDownList ID="postalCodesDropDown" runat="server"/> <ajaxToolkit:CascadingDropDown ID="postalCodesCascadingDropDown" TargetControlID="postalCodesDropDown" Category="PostalCode" PromptText="Please select postalcode" LoadingText="[Loading postalcodes...]" ServicePath="GeonamesService.asmx" ServiceMethod="GetPostalCodesByCountry" ParentControlID="countriesDropDown" runat="server"/>

The source code can be downloaded here: IStaySharp.AJAXSample.rar (332,56 KB)

Thursday, January 25, 2007 2:13:28 AM (Romance Standard Time, UTC+01:00)  #    Comments [1] -
 | 
 Sunday, January 14, 2007

Yep, version 1.0 of the Web Client Software Factory has been released. Release 2 is expected around the end of June 2007.

Sunday, January 14, 2007 5:22:56 PM (Romance Standard Time, UTC+01:00)  #    Comments [1] -

 Wednesday, January 10, 2007

Virtual PC 2007 RC1 has been released, and can be downloaded on the Microsoft Connect site, if you participated in the beta tests. The main new features are:

  • Support for Windows Vista™ as a host operating system
  • Support for Windows Vista™  as a guest operating system
  • Support for 64-bit host operating systems
  • Support for hardware-assisted virtualization
  • Built-in support for network installations

More details about the release notes can also be downloaded on the Microsoft Connect site.

Wednesday, January 10, 2007 12:04:03 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 | 
 Saturday, December 30, 2006

The Validation Application Block (VAB) of the upcoming Enterprise Library v3, uses attributes to describe validations. This gives us for example the opportunity to generate ASP.NET validators based on the attributes decorated on the properties.

Take for example the NotNullValidator of VAB, this can be translated to a RequiredFieldValidator, whereas the RegexValidator can be translated to RegularExpressionValidator. You can go further with the NotNullValidator and mark required fields with a different backcolor and adding an asterix (*) to the end of the control.

I am big fan of the DetailsView control, you can simply bind a DataSource control to it, and it will automatically provide you with a caption to each control and two-way binding. Below you find an example how you can extend the BoundField control, that investigates the NotNullValidator attribute of VAB. Note that I am currently extending it for the other set of validators and in a more OO way. More info will follow later.

BoundFieldEx.cs - Copy Code
public class BoundFieldEx : System.Web.UI.WebControls.BoundField { public override void InitializeCell( DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex) { base.InitializeCell(cell, cellType, rowState, rowIndex); if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) || ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal)) { TextBox textBox = null; if (cell != null && cell.Controls.Count > 0) textBox = cell.Controls[0] as TextBox; if (textBox != null) { Type dataItemType = null; if (DataBinder.GetDataItem(base.Control) != null) dataItemType = DataBinder.GetDataItem(base.Control).GetType(); if (dataItemType != null) { ValidatorAttribute attribute = IsRequired(dataItemType, base.DataField); if (attribute != null) { string textBoxID = this.DataField; textBox.ID = textBoxID; RequiredFieldValidator validator = new RequiredFieldValidator(); validator.ControlToValidate = textBoxID; validator.ID = string.Concat("RequiredValidatorOf", textBoxID); validator.Display = ValidatorDisplay.Dynamic; validator.ErrorMessage = attribute.MessageTemplate; cell.Controls.Add(validator); } } } } } private ValidatorAttribute IsRequired(Type dataType, string property) { PropertyInfo propertyInfo = dataType.GetProperty(property); if (propertyInfo != null) { foreach (Attribute attribute in propertyInfo.GetCustomAttributes(true)) { if (attribute is NotNullValidatorAttribute) return attribute as ValidatorAttribute; } } return null; } }

Now you create a custom business object, called Customer, and bind it to the DetailsView through an ObjectDataSource.

Customer.cs - Copy Code
public class Customer { private string _firstName; private string _lastName; [NotNullValidator(MessageTemplate="Firstname cannot be empty")] public string FirstName { get { return _firstName; } set { _firstName = value; } } [NotNullValidator(MessageTemplate="Lastname cannot be empty")] public string LastName { get { return _lastName; } set { _lastName = value; } } public Customer Fill() { Customer customer = new Customer(); customer.FirstName = "Christoph"; customer.LastName = "De Baene"; return customer; } }

Inside your aspx page you have something like

Customer.aspx - Copy Code
<asp:ObjectDataSource id="customerDataSource" TypeName="IStaySharp.Business.Customer, IStaySharp.Business" DataObjectTypeName="IStaySharp.Business.Customer, IStaySharp.Business" SelectMethod="Fill" runat="server"> </asp:ObjectDataSource> <asp:ValidationSummary runat="server"/> <asp:DetailsView DataSourceID="customerDataSource" DefaultMode="Edit" AutoGenerateRows="false" runat="server"> <Fields> <rfx:BoundField HeaderText="Firstname" DataField="FirstName"/> <rfx:BoundField HeaderText="Lastname" DataField="LastName"/> </Fields> </asp:DetailsView>

Here is the result if you leave the properties empty:

Saturday, December 30, 2006 12:31:05 AM (Romance Standard Time, UTC+01:00)  #    Comments [9] -

 Sunday, December 24, 2006

That's what I call a christmas present. A CTP for Enterprise Library v3.0 has been released on CodePlex. More info can be found in this post.

Sunday, December 24, 2006 1:16:47 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Monday, December 11, 2006
Version 0.23 of SyntaxColor4Writer is compiled against the new build release of Windows Live Writer 1.0.1 (Build 6) and Actipro Code Highlighter v4.0.0041.
Monday, December 11, 2006 12:55:38 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Thursday, October 05, 2006

A new version of CruiseControl.NET has been released. The release notes of version 1.1 can be found here. This is the defacto standard tool if you want to continuous integration together with unit testing, code metrics, code analysis, etc.

Thursday, October 05, 2006 12:48:25 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

Recently I switched from RSSBandit to GreatNews as RSS reader (noticed by a post from Bert Jansen).

The speed for aggregating feeds using GreatNews is really fast! I think it was better called SpeedNews ;). Besides that, it has a nice user-interface and all config & feed data is kept in the installation folder. This means that no installation (MSI) is required, and that it can easily be deployed to other computers.

Thursday, October 05, 2006 2:31:16 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 | 
 Wednesday, September 27, 2006

Cassini is a ASP.NET sample application that shows how to write a web server using .NET. This means that you can host ASP.NET using the ASP.NET hosting APIs (System.Web.Hosting). This is really an alternative to IIS. There is also a second project called UltiDev Cassini Web Server which is based on the Cassini source with the following additional features:

  • Comes ready for distribution with Visual Studio ASP.NET applications
  • Runs as a windows service
  • Hosts and runs multiple ASP.NET applications
  • Provides management UI and simple API for configuring web applications
  • Comes in two flavors: 2.0 version for ASP.NET 2.0 applications, and 1.1 for applications compiled for ASP.NET 1.1

If you have the need for an offline version of your ASP.NET application, where easy deployment is required (without IIS), then this is a very good solution.

Wednesday, September 27, 2006 12:16:18 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Sunday, September 24, 2006

Ubuntu is a free linux-based operating system. Ubuntu works very well on Virtual PC, and I didn't encounter any problems during installation. A detailed step-by-step explanation can be found on the documentation site of Ubuntu, How To - Configure Ubuntu for Microsoft Virtual PC 2004.

Setting Ubuntu to the same screen resolution as the host in full-screen mode didn't worked for me. I tried the following post, but without any success.

One of the reasons for installing Ubuntu, was to see if my blog site rendered correctly in Firefox. Only the line under the post title was not positioned correctly. I will update the 'business' theme soon.

Sunday, September 24, 2006 5:32:17 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Friday, September 22, 2006

DasBlog 1.9 is released. It's a major update with a lot of extra features and fixes. I contributed to this release for improving DasBlog in a multi-user setup. The following features has been added (will update the documentation on dasblog.info):

  • Top Posters macro & Profile Combo control
  • Every admin/contributor can create/edit a personal profile page
  • A Contributor can be notified by mail for certain events and can be configured through the 'User Settings' screen
    • Notify when a new post has been added
    • Notify when comments has been added for ALL posts
    • Notify when comments has been added for OWN posts

I also created a new theme called 'business', which is running on my weblog now. It's not yet included in this release, but it's available through the subversion repository. I am also planning to create a theme, based on 'business', for in a multi-user setup.

Soon I will update RealDN (corporate blog of my company I am working for) to DasBlog 1.9.

Friday, September 22, 2006 11:58:40 AM (Romance Standard Time, UTC+01:00)  #    Comments [2] -

 Friday, August 18, 2006

Windows Live Writer is a desktop application that makes it easier to compose compelling blog posts using Windows Live Spaces or your current blog service. For Windows Live Writer I created a plugin called SyntaxColor4Writer that enables you to embed syntax highlighting in your blog posts. More details about SyntaxColor4Writer can be found here. This is how the plugin looks:

This is an example of a xml fragment generated by SyntaxColor4Writer:

<system.web> <compilation defaultLanguage="VB" debug="true" /> <customErrors mode="RemoteOnly" /> </system.web>

 

Friday, August 18, 2006 2:17:50 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 |  | 
 Tuesday, May 23, 2006

That's right, a public preview of Office 2007 Beta 2 is available. You can download the bits from here. Note that right now it is very difficult to connect to the server, due to high traffic.

Tuesday, May 23, 2006 10:10:13 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 | 
 Monday, April 24, 2006

BindingListView<T> is a project hosted on GotDotNet that gives you search, sorting and filtering capabilities to a plain BindingList. For example if you have the following Person entity:

public class Person
{
    string firstName = string
.Empty;
    int age = 0;

    public string FirstName
    {
       
get { return firstName; }
        set { firstName = value; }
    }

    public int Age
    {
       
get { return age; }
       
set { age = value; }
   
}

    public Person(string firstName, int age)
   
{
       
this.firstName = firstName;
       
this.age = age;
   
}
}

And you want to have a collection of persons bind to a datagrid, you can simply write the following:

BindingList<Person> persons = new BindingList<Person>();
persons.Add(
new Person("Bill", 45));
persons.Add(
new Person("Gert", 33));
persons.Add(
new Person("Johan", 12));
persons.Add(
new Person("An", 27));

personsGrid.DataSource = persons;

What if you need to do some filtering, or simply sorting on the datagrid? Therefore you would need to create a custom collection class that implements a bunch of interfaces for having sorting, filtering and searching capabilities.

The BindingListView<T> class has all these functionalities built-in. You simply have to pass a list, and bind the BindingListView to the datagrid. The same way you would do with a DataSet and DataView. This means:

BindingListView<Person> personsView = new BindingListView<Person>(persons);
personsGrid.DataSource = personsView;

Sorting on a BindingListView is done through the Sort property, the same as on a DataView. For example:

personsView.Sort = "FirstName";

Filtering is done through the Filter property and uses anonymous delegates. So for example to filter all persons that are less than 30, you can write:

personsView.Filter = BindingListView<Person>.CreateItemFilter(new Predicate<Person>(
    delegate(Person
person)
    {
       
return
(person.Age < 30);
    }
));

You can also merge multiple sources to one view (functionality that the DataView doesn't support) through the AggregatedBindingListView<T>.

Monday, April 24, 2006 11:42:21 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Sunday, April 23, 2006

One of the ways for extending the WebBrowser 2.0 control is to inherit from WebBrowserSiteBase. According to the documentation, you have to override the method CreateWebBrowserSiteBase and return your specific implementation of WebBrowserSiteBase.

Everything is there to plug-in your implementation of WebBrowserSiteBase, but the problem is that the constructor of WebBrowserSiteBase is marked as internal, and so there is no way to inherit from. I am pretty sure that it was possible with the beta release of .NET 2.0, but for some reason they marked it as internal in the RTM version. This means that implementing some interfaces that are described here are not possible.

I am planning to release a .NET 2005 version of my IStaySharp.WebBrowser project. More info coming soon.

Sunday, April 23, 2006 7:43:56 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 | 
 Thursday, April 13, 2006

The Service Factory is a cohesive collection of various forms of guidance that have been build with the primary goal of helping you build high quality connected solutions in a more consistent way with less effort.

Check it out: http://practices.gotdotnet.com/projects/svcfactory

Thursday, April 13, 2006 11:35:18 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

Finally I have updated my site, called IStaySharp to MediaWiki. MediaWiki is one of the best wiki based engines available and it's written in PHP and MySQL. Thankfully my hosting, webhost4life, has PHP & MySQL support.

The intention of IStaySharp is to document and archive my code snippets, articles, components, projects, etc. that I am working on, and to share my experiences that I encounter during my .NET development. Visitors to the site can use the discussion page to give feedback, remarks, suggestions, etc. to the associated page.

I didn't encounter much problems when installing MediaWiki on webhost4life, except the e-mailing didn't work directly. The problem was that MediaWiki uses the format: 'myname <myname@domain.com>' in the 'to' field of the mail function, and with the current settings and setup of webhost4life this resulted in an invalid address. Therefore I had to change the method 'toString()' of the 'MailAddress' class inside 'UserMailer.php' to

function toString()
{
     return $this->address;  
}

instead of

function toString()
{
  if( $this->name != '' ) {
   return wfQuotedPrintable( $this->name ) . " <" . $this->address . ">";
  } else {
   return $this->address;
  }
}

IStaySharp uses also the extension that I wrote for having syntax highlighting. Some other nice extensions are coming!

Thursday, April 13, 2006 11:10:25 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Wednesday, March 29, 2006

When reviewing code, you see a lot of 'bad' use of exception handling. As Pieter Gheysens mentioned, you see a lot of code that looks like:

try
{
   // code statements
}
catch(Exception exc)
{
   throw exc;
}

No extra logic defined inside the catch-block, like logging, and when it is meant to re-throw an exception, the 'throw' statement must be used, instead of 'throw ex'. The statement 'throw ex' will erase the original stacktrace. Best practice for exception handling is

try
{
   // code that could throw an exception
}
catch(Exception exc)
{
   // log exception
   throw;
}

In case of a traditional layered architecture, UI, Business Logic (BL) & Data Access Logic (DAL), you will catch a DAL exception inside the BL layer, and translate it to a 'meaningfull' business exception. Each layer has a specific purpose and domain, and so are the exceptions!

It's also a good idea to subscribe to the Application.ThreadException (in case of a form application) and do the logging in there. Here log4net is used as logging tool.

ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
   log.Error("Application error", e.Exception);
   // show custom error dialog or throw
}

Wednesday, March 29, 2006 12:50:13 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Thursday, March 09, 2006

Modern GPUs are increasing in programmability and these chips can do more than just graphical computations. They can now be used as a coprocessor, and they can be integrated for a set of tasks. GPGPU (General-Purpose compuation on GPUs) is such an initiative that contains a catalog where the GPU can be used for general-purpose computation.

The big challenge, is to translate the everyday applications to two-dimensional graphic functions, like texture mapping. In other words: Pretend that everything is a game (source). 

As an example in this article and results, a quicksort algorithm of 18 million records in Visual C++ took 21 seconds, while the GPU took 2 seconds! What are the results for a Quad SLI setup? ;-)

Microsoft research is apparently working on a system that simplifies the programming of GPU to general-purpose tasks, it's called Accelerator (simplified programming of graphics processing units for general-purpose uses via data-parallelism).

Thursday, March 09, 2006 12:41:25 AM (Romance Standard Time, UTC+01:00)  #    Comments [0] -
 |  | 
 Wednesday, March 01, 2006

Continuous integration is the process that continuously build, analyze and test your sources. In many cases the process is triggered when changes are notified in the version control system, like VSS, CVS, etc. Martin Fowler has a good article about continuous integration.

In the .NET world, the most famous tool is CruiseControl.NET in combination with NAnt & NUnit. Getting an e-mail or popup from CruiseControl.NET is nice when a build is broken, but notifying the build status through traffic lights is much cooler.

Michael Swanson integrated CC.NET with the Ambient Orb. I think that the Ambient Orb is not an option for Europe, but you can integrate by using the X10 home automation technology. A good article about integrating X10 with .NET can be found on Coding4Fun and is called Controlling Lights with .NET.

Here are some (other) implementations:

 
 

I am going for a walk this evening, and I think that tomorrow a traffic light will be missing :-D

Wednesday, March 01, 2006 11:58:46 PM (Romance Standard Time, UTC+01:00)  #    Comments [0] -

 Thursday, February 23, 2006

CAB is an application block for building smart clients in .NET 2.0 and contains proven practices for building complex UI forms with so called SmartParts and Workspaces. The DeckWorkspace enables you to show and hide controls and SmartParts in an overlapped manner with no visible frame.

If you switch between controls, you will notice that the controls are painted while there are initializing. During the loading you will see that there is some overlapping and it doesn't give you a professional user experience.

Therefore I extended the DeckWorkspace, so that the the controls are only redrawed when they are initialized. This can be done through the WM_SETREDRAW message. Note that this technique can also be used for other workspaces.

public class DeckWorkspaceEx: DeckWorkspace

   int freezePainting = 0;
   const int WM_SETREDRAW = 0xB;

   [DllImport("User32")]
   static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

   protected void FreezePaintingOn()
   {
      if (IsHandleCreated && this.Visible)
      {
         if (0 == freezePainting++)
         {
            SendMessage(Handle, WM_SETREDRAW, 0, 0);
         }
      }
   }

   protected void FreezePaintingOff()
   {
      if (freezePainting != 0)
      {
         if (0 == --freezePainting)
         {
            SendMessage(Handle, WM_SETREDRAW, 1, 0);
            Invalidate(true);
         }
      }
   }

   protected override void OnActivate(Control smartPart)
   {
      FreezePaintingOn();
      try 
      {
         base.OnActivate(smartPart);
      }
      finally 
      {
         FreezePaintingOff();
      }
   }

   protected override void OnClose(Control smartPart)
   {   
      FreezePaintingOn();
      try 
      {
         base.OnClose(smartPart);
      }
      finally 
      {
         FreezePaintingOff();
      }
   }

   protected override void OnHide(Control smartPart)
   {
      FreezePaintingOn();
      try 
      {
         base.OnHide(smartPart);
      }
      finally 
      {
         FreezePaintingOff();
      }
   }   

   protected override