avr. 23

Some explanation 

Depending of the browser, some control may need to be rendered differently. By default the .NET framework works with "Control Adapters", id est, some classes that will be plugged into the rendering process.

How does it works ? When the server receives a request, it will try to find which browser does the request, based on the user agent or on HTTP headers for example. To do it rely on some browser definition files (of extension .browser). To see them, please go on %windir%/Microsoft.NET/Framework/<version>/CONFIG/Browsers.

When the server has identified the browser (at worse, it would be identified as a "Default" browser), and that it needs to render a control, it will look if there is some control adapters plugged for this kind of control. If there are some, they will be in charge of the rendering. If not, the control will render himself. Note that an adapter can redirect / delegate some treatment to the control.

Creating a basic Adapter for TextBoxes

  • Let's create a solution with a website and a "Web Control Class Library" (named "MyControlLibrary")
  • Let's add a new class in the library for the adapter. Note that by convention, an adapter will always be named "ControlNameAdapter" where "ControlName" is the control we want to adapt. Here we'll so create the "TextBoxAdapter"

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.Adapters;

 

namespace MyControlLibrary

{

   public class TextBoxAdapter : WebControlAdapter

   {

      /// <summary>

      /// If you need to access the adapted control, the framework advice to expose

      /// a private method encapsulating the Adapter's Control property.

      ///

      /// We can cast it without doing any test, as by naming convention,

      /// this adapter shall only be used for adapting Textboxes (or derived types)

      /// </summary>

      private TextBox Control

      {

         get { return (TextBox)base.Control; }

      }

 

      /// <summary>

      /// Let's add some extra attribute in our control's begin tag

      /// </summary>

      protected override void RenderBeginTag(HtmlTextWriter writer)

      {

         writer.AddAttribute("MyNewAttribute", "This has been set in the adapter");

         writer.AddAttribute("ControlType", this.Control.GetType().FullName);

 

         base.RenderBeginTag(writer);

      }

   }

}

How to use it in a website ?

The mapping between a control and its adapter is done at the website level, using the browser definitions.

  • In the website, add the special folder "App_Browsers"
  • In the folder add a new browser definition file

We have several solutions here. The simplest is to add some capabilities to an existing browser. We can either decide to do this for all browser, or for a specific browser.

<browsers>

<!--

   Here we extend the "Default" browser (ie the basis browser from which all other

   browser derive (see in %windir%/Microsoft.NET/Framework/<Version>/CONFIG/Browsers)

 

   To extend only a specific browser, replace the refID by another one eg :

      refID="IE" for all versions of IE

      or refID="IE50" for only the 5.0 version

   -->

   <browser refID="Default">

      <controlAdapters>

         <adapter adapterType="MyControlLibrary.TextBoxAdapter"

                  controlType="System.Web.UI.WebControls.TextBox" />

      </controlAdapters>

   </browser>

</browsers>

How to use this functionality for testing purposes ?

Let's explain my context : in a TDD environment all code (and so pages) are tested before being written. To do so, we can use for instance basic HTTP request that will call my page and then validate them using any HTML parsing. In order to facilitate the testing, we may want to base our research on some extra tags. That's where Control Adapters may enter in the game. As a consequence we want some control adapters to be used only for testing. The simplest way to do so is to consider that our testing framework will use a "special browser" by giving some clues in the HTTP Headers or in the user agent.

For example by using this code, we could make request by simulating a IE 5.0 browser, and sending an extra hint.

HttpWebRequest request = HttpWebRequest.Create("http://localhost/MyPage.aspx")

   as HttpWebRequest;

request.UserAgent

   = "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; MyTestSimulator)";

At the end, we could update our browser file to have this kind of definition :

<browsers>

   <!-- Let's create a new browser, extending another one,

   eg IE50, Mozilla, MozillaFirefox, Default, ... -->

   <browser id="MyTestSimulator" parentID="IE50">

      <!-- Let's here base our research on our user agent hint to match our

      "special test browser"

      -->

      <identification>

         <userAgent match="MyTestSimulator" />

      </identification>

 

      <controlAdapters>

         <adapter adapterType="MyControlLibrary.TextBoxAdapter"

                  controlType="System.Web.UI.WebControls.TextBox" />

      </controlAdapters>

   </browser>

</browsers>

Tags: | | | |
avr. 10

You will find on a Scott Gu's post a list of nice debugger visualiser.

How to install them ? Simply copy the DLLs in the

  • for a single user
    • C:\Documents and Settings\UserName\My Documents\Visual Studio 2005\Visualizers
  • for all users
    • C:\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\Visualizers
Tags:
avr. 07

If you dynamically add worksheets, you may need to delete them also. How to do that ? Simple. You can write a simple function as :

/// <summary>

/// Delete all the worksheet from the given collection, except the ones that are named

/// accordingly to one of the given name

/// </summary>

/// <param name="worksheets">The collection of worksheet we want to clean</param>

/// <param name="excludedNames">The names of the worksheet we want to keep</param>

public static void DeleteWorksheets(IExcel.Sheets worksheets, params string[] excludedNames)

{

   for ( int i = worksheets.Count; i > 0; i-- )

   {

      IExcel.Worksheet sheet = worksheets[i] as IExcel.Worksheet;

      if ( !excludedNames.Contains(sheet.Name) )

         sheet.Delete();

   }

}

How to use it ? Well if you are in a sheet code and that you want to delete all the sheets except the current one, you can do :

ExcelUtils.DeleteWorksheets(Globals.ThisWorkbook.Worksheets, this.Name);

Almost good. You will simply notice that each time Excel wants to delete a sheet, you will get a popup asking to confirm the deletion. How to bypass it ? Let's modify our function as follows :

/// <summary>

/// Delete all the worksheet from the given collection, except the ones that are named

/// accordingly to one of the given name

/// </summary>

/// <param name="worksheets">The collection of worksheet we want to clean</param>

/// <param name="excludedNames">The names of the worksheet we want to keep</param>

public static void DeleteWorksheets(IExcel.Sheets worksheets, params string[] excludedNames)

{

   //1. DisplayAlerts = true : will display confirmation popup for the deletion.

   //   to do a silent deletion, we'll set it to false (but save the old values to restore it)

   bool displayAlerts = worksheets.Application.DisplayAlerts;

   try

   {

      worksheets.Application.DisplayAlerts = false;

 

      for ( int i = worksheets.Count; i > 0; i-- )

      {

         IExcel.Worksheet sheet = worksheets[i] as IExcel.Worksheet;

         if ( !excludedNames.Contains(sheet.Name) )

            sheet.Delete();

      }

   }

   finally

   {

      worksheets.Application.DisplayAlerts = displayAlerts;

   }

}

And here we are !
Tags: |
avr. 07

You may have noticed that the logging is different between TFS 2005 and TFS 2008. Indeed they have changed the verbosity level of the logging : it was normal for TFS 2005 and it is now diagnostic by default.

How can we control it to reset it to normal?

Simply by changing the value of some parameters that are sent to MSBuild. For that, you can simply edit the "TFSBuild.rsp" file that has been generated with your "TFSBuild.proj" file. See one example below :

# This is a response file for MSBuild

# Add custom MSBuild command line options in this file

 

# We can control here the "verbosity" level of the logging. The possible values are :

#     quiet

#     minimal

#     normal

#     detailed

#     diagnostic

/fileloggerparameters:Verbosity=minimal

How can you know the possible switch you can set here and their values ? Simply check the MSBuild help. You can also refer to the blog of Aaron Hallberg and his post about verbosity.

avr. 02

Here is how the VISUG present us the presentation of Juval Lowy that will be done this thursday 03 April.

He will present us "Demonstrating WCF – Beyond the Endpoints".

I just write this (very short) post to tell that there is still some seats available for this event. Visit the website of the VISUG and join me there !

Tags: