Monday, December 22, 2008

Analyzing Risk

Just read a great article about risk on MSDN. While evaluating risks in my daily job, it puts some things in context (like the top 10 project risks) .

Tuesday, December 16, 2008

Creating a configuration section

In general, a lot of application are using the appSettings section of a config file for storing application parameters. A major drawback of this practice, is the lack of prior knowledge about the format and default value of these parameters, so you need to program all this functionality yourself.
A better way to provide your application with configuration values, is the use of a configuration section. Instead of using the appSettings node, you can specify your own.
The key to your own configuration section is the System.Configuration namespace.
You write your own class, but should inherit ConfigurationSection.
Now you can spice up your properties in this class with the ConfigurationProperty attribute. Validation can be programmed with the attributes
  • IntegerValidatorAttribute
  • LongValidatorAttribute
  • RegexStringValidatorAttribute
  • StringValidatorAttribute
  • TimeSpanValidatorAttribute


For example:

public class TestConfigurationSection : ConfigurationSection
{
// Empty Construct
public TestConfigurationSection() { }

// default string property
[ConfigurationProperty("deliveryStore", IsRequired = true)]
public string DeliveryStore
{
get
{
return (string)this["deliveryStore"];
}
set
{
this["deliveryStore"] = value;
}
}
//uri types will work too
[ConfigurationProperty("serviceUrl", DefaultValue = "http://192.168.1.10/MessageService", IsRequired = false)]
public Uri ServiceUrl
{
get
{
return (Uri)this["serviceUrl"];
}
set
{
this["serviceUrl"] = value;
}
}

[ConfigurationProperty("timeOut", DefaultValue = "0:00:20")]
[TimeSpanValidator(MinValueString = "0:00:05", MaxValueString = "0:05:00", ExcludeRange = false)]
public TimeSpan TimeOut
{
get
{
return (TimeSpan)this["timeOut"];
}
set
{
this["timeOut"] = value;
}
}
}


To use this configuration section in your config, you need to add it to the configsections node, for instance:

<configSections>
<section name="testConfig" type="NJV.Utils.TestConfigurationSection, NJV.Utils"/>
</configSections>
<testConfig
deliveryStore="D:\Test"
serviceUrl="http://10.0.0.9/MessageService"
timeOut="0:00:20"
/>


Now you've the settings defined and validation setup. To read these values, you can use the following code:

TestConfigSection config = (TestConfigSection)System.Configuration.ConfigurationManager.GetSection("testConfig");
TimeSpan timeout = config.TimeOut;
string deliveryLocation = config.DeliveryStore;
Uri serviceLocation = config.ServiceUrl;


The only drawback here is, you should be sure to have a testConfig section defined in your config, and it should be of the correct type. So maybe there could be some type and null reference checking on line 1:

TestConfigSection config = System.Configuration.ConfigurationManager.GetSection("testConfig") as TestConfigSection;
if (config==null)
{
throw new ApplicationException("No configuration available");
}

Sunday, December 14, 2008

Certified SQL Server Developer

With the wave of beta exams the last month, I've earned three new certifications:
MCTS: SQL Server 2008, Database Development, MCTS: SQL Server 2008, Business Intelligence Development and Maintenance and MCITP: Database Developer 2008.

Quite funny the SQL Developer is under the MCITP certification brand, instead of the MCPD.

Thursday, October 16, 2008

Presentation on .NET 3.5

I did a presentation on .NET 3.5 last evening for my company. The presentation with demo code is posted on my SkyDrive. The presentation went well... I was a little bit nervous, but it went away quickly after I'd started.

I've made use of the demo pptPlex functionality from Office Labs. The version posted here, doesn't have these nice little extra's, but see the pptPlex website for more info about this tool. I didn't used pptPlex during the presentation the whole time... during the presentation I noticed I was presenting the wrong sheets, with old content on it. I changed back to normal presentation mode. Afterwards, I found the 'clear cache' under 'Learn more' to tidy up the cache and got the latest version of the sheets (but such a strange place for such an option).

Downloads

Thursday, October 9, 2008

PandP Cheat Sheet

A cheat sheet with all available patterns & practices has just been made available on Codeplex. It gives a grouped overview of all available p&p products.

Wednesday, October 8, 2008

Mount VHD in host OS

Just discovered... mounting a VHD is possible!


The registry should be edited with:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD\shell]
@="Mount"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD\shell\Dismount]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD\shell\Dismount\command]
@="\"C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.exe\" /u \"%1\""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD\shell\Mount]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Virtual.Machine.HD\shell\Mount\command]
@="\"C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.exe\" /p \"%1\""

[HKEY_CLASSES_ROOT\.vhd]
@="Virtual.Machine.HD"

Monday, October 6, 2008

Code Review Checklist for ASP.NET

I'm supposed to do a code review for an externally developed ASP.NET application on my job this week. I'm posting here some guidance to perform this review.
The goal of the review should be
  • The code satisfies the requirements
  • The code is robust (ie stable and should be descriptive in case of error)
  • The code handles wrong inputs (SQL/XSS Injection!)
  • The code is scalable
  • The code is extensible and maintainable
(free to Zysman).

Microsoft has a couple of checklists about these topics (unfortunately for .NET 1.1). Useful are: Securing ASP.NET, Security Review for Managed Code and Code Review for .NET Application Performance. And just found the guide for the .NET 2.0 version: How To: Perform a Security Code Review.

Monday, August 18, 2008

Filter tripple Gmail Starred items from Outlook 2007 To-Do List

I love Outlook 2007 and the integration of flagged mail, tasks and other items. I read my Gmail with the IMAP connector. One drawback is that Starred items will show up in your T-Do list as Flagged items. Well, I can live with that, but actually they show up three times. One time as a mail item in my Inbox, one time in the Starred folder, and one time in the All Mail folder.
Hey, I know I've got a lot to do, but this view isn't workable.

The solution is to right click the list, and choose 'Customize Current View...', there you can change the filter for the view, and in the Advanced tab you say, don't show items where the In Folder contains Starred or All Items.
The stupidity of the standard filter is that the two statements two aren't combined with the OR specifier... hey, that's first grade logica. So switch to SQL tab, ignore the message about not being able to use the other three tabs anymore, and change the OR in an AND...

Problem solved.

Saturday, July 19, 2008

First 3.5 Certifications

MCTS: Framework 3.5, ASP.NET Development Logo
Last week I had finaly the results of my beta exam 70-562 for the MCTS ASP.NET 3.5 certificiation. Microsoft let me know that I have passed the exam! So it is my first VS2008 certificate.
Update:I also had a mail two days later I succeeded in the beta ADO.NET 3.5 exam. That's two down, still four to go ;)

Friday, July 11, 2008

Backup your files with WinRar

A while ago (actualy, three and a half years), I've made a backupscript with winrar.  With these four files and your windows task scheduler, you've a full featured backup system, producing rar-files per run. The incremental version makes use of the archive flag of the filesystem. The full backup justs proces all the files. Backuplist.txt contains a list of all the folders to include. Exludefile.txt contains all the folders inside the included folders to exclude.

Incremental.cmd

"c:\program files\winrar\winrar.exe" a -ac -ao -ep2 -os -ow -IBCK -inul -r -agYY-MM-DD -x@B:\backup\excludefile.txt B:\backup\incremental- @B:\backup\backuplist.txt
REM -ac clear archive flag on files
REM -ao for archive flag only files
REM -ag[format] to include date in filename
REM -ep2 Store full file paths
REM -OS - save NTFS streams
REM -OW - process file security information

Full.cmd

"c:\program files\winrar\winrar.exe" a -ac -ep2 -os -ow -r -IBCK -inul -agYY-MM-DD -x@B:\backup\excludefile.txt B:\backup\full- @B:\backup\backuplist.txt
REM -ac clear archive flag on files
REM -ag[format] to include date in filename
REM -ep2 Store full file paths
REM -OS - save NTFS streams
REM -OW - process file security information

backuplist.txt

D:\Data
D:\My Documents
C:\Documents and Settings\User\StartMenu
C:\Documents and Settings\User\Desktop
C:\Documents and Settings\User\Application Data\Mozilla

excludefile.txt

C:\Documents and Settings\User\Application Data\Mozilla\Firefox\Profiles\default.xyz\Cache

Wednesday, July 2, 2008

Compiling documents the OpenXML way

Today, I've got a RFC about the automatically generation of a document. De document should be a write-out of a thesaurus, which is contained in a SQL database. It should run server-sided, and should produce the document with the ease of a push of the button.
Besides the standard list of words, the document should contain page-numbers. In the past, this was done by writing out html, saving the document with the .doc extension and pushing the file with the right MIME headers. But with this approach, insertion of page numbers on each page is quite a burden (if possible at all)... so enter OpenXML.

The other scenario, using mail-merge functionality, isn't used. I want the merge takes place on the server, not on the client.

The code here is just programming with XML and the System.IO.Packaging namespace, introduced in .NET 3.0. I still haven't tried the OpenXML SDK, so you should know what you're doing with adding XML fragments and their relations into the package.
The solution is quite straightforward, and it won't be difficult to expand this to your own needs.

We start by referencing the System.IO.Packaging namespace. It is delivered in the WindowsBase GAC dll. Add a reference to the WindowsBase and you can build your own Package from scratch:

private void Load(string documentPath)
{
Package pkgOutputDoc = null;
pkgOutputDoc = Package.Open(@"c:\work\test.docx", FileMode.Create, FileAccess.ReadWrite);
Uri uri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart partDocumentXML = pkgOutputDoc.CreatePart(uri,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");

StreamWriter streamStartPart = new StreamWriter(partDocumentXML.GetStream(FileMode.Create, FileAccess.Write));
XmlDocument xdoc = new XmlDocument();
xdoc.Load(@"C:\work\document.xml");
FillDocument(xdoc);
xdoc.Save(streamStartPart);
streamStartPart.Close();
pkgOutputDoc.Flush();

pkgOutputDoc.CreateRelationship(uri, TargetMode.Internal,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
"rId1");
pkgOutputDoc.Flush();
pkgOutputDoc.Close();
}


I've added all the xml fragments I've used as embedded resources to my dll, so it is quite easy for me to version and deploy this solution. The added document.xml, the main content of my docx file, is expanded by generating custom xml, based on the database content.
I've read my database content into a dictionary, and I'm generating the xml based on each keyword in my database.

<w:p>
<w:r>
<w:t>Term</w:t>
</w:r>
<w:r>
<w:br />
</w:r>
<w:r>
<w:tab />
<w:t>SN</w:t>
</w:r>
<w:r>
<w:tab />
<w:t>scope note for Term</w:t>
</w:r>
<w:r>
<w:br />
</w:r>
<w:r>
<w:tab />
<w:t>UF</w:t>
</w:r>
<w:r>
<w:tab />
<w:t>Term B</w:t>
</w:r>
<w:r>
<w:br />
</w:r>
<w:r>
<w:tab />
<w:t>RT</w:t>
</w:r>
<w:r>
<w:tab />
<w:t>Term C</w:t>
</w:r>
<w:r>
<w:br />
</w:r>
</w:p>

This xml fragment is built by the following code

private void FillDocument(XmlDocument xdoc)
{
XmlNamespaceManager nsMgr = new XmlNamespaceManager(new NameTable());

string wNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
nsMgr.AddNamespace("w", wNamespace);

XmlNode wBody = xdoc.SelectSingleNode("/w:document/w:body", nsMgr);
//begin inserting at the last defined paragraph
XmlNode lastParagraph = xdoc.SelectSingleNode("/w:document/w:body/w:p[last()]", nsMgr);

Dictionary<string, List<RelatedKeyword>> thesaurus = ThesaurusList.GetThesaurus();

foreach (string keyword in thesaurus.Keys)
{
XmlElement thesaurusTerm = xdoc.CreateElement("w", "p", wNamespace);
wBody.InsertAfter(thesaurusTerm, lastParagraph);
lastParagraph = thesaurusTerm;

XmlElement thesaurusRterm = xdoc.CreateElement("w", "r", wNamespace);
XmlElement thesaurusText = xdoc.CreateElement("w", "t", wNamespace);
XmlElement thesaurusRbreak = xdoc.CreateElement("w", "r", wNamespace);
XmlElement thesaurusBreak = xdoc.CreateElement("w", "br", wNamespace);

thesaurusText.InnerText = keyword;

thesaurusTerm.AppendChild(thesaurusRterm);
thesaurusRterm.AppendChild(thesaurusText);

thesaurusTerm.AppendChild(thesaurusRbreak);
thesaurusRbreak.AppendChild(thesaurusBreak);

foreach (RelatedKeyword relatedKeyword in thesaurus[keyword])
{
XmlElement termTypeR = xdoc.CreateElement("w", "r", wNamespace);
XmlElement termDescriptionR = xdoc.CreateElement("w", "r", wNamespace);
XmlElement termBreakR = xdoc.CreateElement("w", "r", wNamespace);
XmlElement termTypeT = xdoc.CreateElement("w", "t", wNamespace);
XmlElement termTypeTab = xdoc.CreateElement("w", "tab", wNamespace);
XmlElement termDescriptionT = xdoc.CreateElement("w", "t", wNamespace);
XmlElement termDescriptionTab = xdoc.CreateElement("w", "tab", wNamespace);
XmlElement termBreak = xdoc.CreateElement("w", "br", wNamespace);



termTypeT.InnerText = relatedKeyword.Relation;
termDescriptionT.InnerText = relatedKeyword.Keyword;

thesaurusTerm.AppendChild(termTypeR);
termTypeR.AppendChild(termTypeTab);
termTypeR.AppendChild(termTypeT);

thesaurusTerm.AppendChild(termDescriptionR);
termDescriptionR.AppendChild(termDescriptionTab);
termDescriptionR.AppendChild(termDescriptionT);

thesaurusTerm.AppendChild(termBreakR);
termBreakR.AppendChild(termBreak);

}
}

}


Now I need to add different xml fragments to the package. The XML fragments for settings, footer and styles are added with this generic function.

AddPart(pkgOutputDoc, uri, partDocumentXML,
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
"rId2",
"/word/settings.xml",
"settings.xml");

/// <summary>
/// Adds the part from an embedded XML to the Package.
/// </summary>
/// <param name="package">The package.</param>
/// <param name="documentUri">The document URI.</param>
/// <param name="partDocumentXML">The part document XML.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="relationshipType">Type of the relationship.</param>
/// <param name="relationId">The relation id.</param>
/// <param name="partPath">The part path.</param>
/// <param name="embeddedFile">The embedded file.</param>
private void AddPart(Package package, Uri documentUri, PackagePart partDocumentXML,
string contentType, string relationshipType, string relationId, string partPath,
string embeddedFile)
{
XmlDocument xdoc = new XmlDocument();
Uri uriPart = new Uri(partPath, UriKind.Relative);
PackagePart part = package.CreatePart(uriPart, contentType);
Uri relativePartUri =
PackUriHelper.GetRelativeUri(documentUri, uriPart);
Stream contentStream = GetEmbeddedXml(embeddedFile);
xdoc.Load(contentStream);
contentStream.Close();
xdoc.Save(part.GetStream());
partDocumentXML.CreateRelationship(relativePartUri, TargetMode.Internal, relationshipType, relationId);
}


The footer can contain the page number by using this xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:ftr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:p>
<w:pPr>
<w:jc w:val="right"/>
</w:pPr>
<w:fldSimple w:instr=" PAGE \* MERGEFORMAT ">
<w:r>
<w:t>1</w:t>
</w:r>
</w:fldSimple>
</w:p>
</w:ftr>


Tuesday, June 24, 2008

MOSS 2007 Certification (70-542)


After my WSS Certificate yesterday, I passed the MOSS Developer exam (70-542) today with 969 points.
So now "I know everything" of InfoPath WebForms, the Business Data Catalog, Sharepoint Search, Audiences, Excel Web Access & Report Services, SharePoint Portals, Policies & Record Repositories, etc. etc... and have the MCTS: Microsoft Office SharePoint Server 2007 – Application Development certification.

Monday, June 23, 2008

WSS3.0 Certification (70-541)

WSS thumbnail I did my 70-541 certification exam today, and passed with a score of 972! Altough the exam was tough, I'm again in the books for the 70-542 (MOSS2007) exam, tomorrow mornig.

So what I've learned? Building webparts, features, site templates, workflows, custom fields, events, etc., etc....

What I've earned? Another MCTS on my CV ;)

Tuesday, June 17, 2008

Generics with Actions

An action is pointer to a function with no return value which you can use for working with generic lists. It looks like the Predicate functions, but the referenced method won't return a boolean value.

Still, the only parameter in the function is of the type of the generic. In this example, I extend the DateRange class with an Action.

An example of such an implementation:

/// <summary>
/// DateRange is a helper class to work with dates
/// </summary>
public class DateRange
{
private DateTime _startDate = DateTime.MinValue;
private DateTime _endDate = DateTime.MaxValue;

public DateTime StartDate
{
get { return _startDate; }
}
public DateTime EndDate
{
get { return _endDate; }
}

public DateRange(DateTime startDate, DateTime endDate)
{
_startDate = startDate;
_endDate = endDate;
}

/// <summary>
/// Gets the IsInPeriod method.
/// </summary>
/// <value>The in period.</value>
public Predicate<DateTime> InPeriod
{
get { return IsInPeriod; }
}

/// <summary>
/// Determines whether the specified date is in the period set by startdate and enddate.
/// </summary>
/// <param name="date">The date.</param>
/// <returns>
/// <c>true</c> if the specified date is in the period; otherwise, <c>false</c>.
/// </returns>
private bool IsInPeriod(DateTime date)
{
if ((date >= StartDate) && (date < EndDate))
{
return true;
}
else
{
return false;
}
}

/// <summary>
/// Gets the WriteNumberOfDaysFromStartDate method.
/// </summary>
/// <value>The write number of days till end.</value>
public Action<DateTime> WriteNumberOfDaysFromStart
{
get { return WriteNumberOfDaysFromStartDate; }
}
/// <summary>
/// Writes the number of days from the start date of the period.
/// </summary>
/// <param name="date">The date.</param>
private void WriteNumberOfDaysFromStartDate(DateTime date)
{
Console.WriteLine("{0} days to go", ((TimeSpan)(date - StartDate)).Days);
}
}


You can now use this conditional predicate with different Generic methods.

public class ActionExamples
{
public static void Main()
{
// fill an example list
List events = new List();
events.Add(DateTime.Now.AddDays(-1));
events.Add(DateTime.Now.AddDays(-2));
events.Add(DateTime.Now);
events.Add(DateTime.Now.AddDays(1));
events.Add(DateTime.Now.AddDays(2));
events.Add(DateTime.Now.AddDays(3));
events.Add(DateTime.Now.AddDays(4));

//create a DateRange object for tomorrow
DateRange nextMonth = new DateRange (new DateTime(2008,7,1), new DateTime(2008,7,31) )

//get events for next month
List nextMonthEvents = events.FindAll(nextMonth.InPeriod);

//write days from start of nextMonth to console
events.ForEach(nextMonth.WriteNumberOfDaysFromStart);
}
}

Monday, June 16, 2008

Generics with Predicates

A predicate is pointer to a boolean function which you can use for querying generic lists.
With these methods, coding against generic lists will be much easier. But one problem with these predicates is that the only parameter in the function is of the type of the generic. A solution for this is refactoring the predicate to a class, where you can provide these parameters to properties or the constructor.

An example of such an implementation:

/// <summary>
/// DateRange is a helper class to work with dates
/// </summary>
public class DateRange
{
private DateTime _startDate = DateTime.MinValue;
private DateTime _endDate = DateTime.MaxValue;

public DateTime StartDate
{
get { return _startDate; }
}
public DateTime EndDate
{
get { return _endDate; }
}

public DateRange(DateTime startDate, DateTime endDate)
{
_startDate = startDate;
_endDate = endDate;
}

/// <summary>
/// Gets the IsInPeriod method.
/// </summary>
/// <value>The in period.</value>
public Predicate<DateTime> InPeriod
{
get { return IsInPeriod; }
}

/// <summary>
/// Determines whether the specified date is in the period set by startdate and enddate.
/// </summary>
/// <param name="date">The date.</param>
/// <returns>
/// <c>true</c> if the specified date is in the period; otherwise, <c>false</c>.
/// </returns>
private bool IsInPeriod(DateTime date)
{
if ((date >= StartDate) && (date < EndDate))
{
return true;
}
else
{
return false;
}
}
}


You can now use this conditional predicate with different Generic methods.

public class PredicateExamples
{
public static void Main()
{
// fill an example list
List events = new List();
events.Add(DateTime.Now.AddDays(-1));
events.Add(DateTime.Now.AddDays(-2));
events.Add(DateTime.Now);
events.Add(DateTime.Now.AddDays(1));
events.Add(DateTime.Now.AddDays(2));
events.Add(DateTime.Now.AddDays(3));
events.Add(DateTime.Now.AddDays(4));

//create a DateRange object for tomorrow
DateRange tomorrow = new DateRange (DateTime.Today.AddDays(1), DateTime.Today.AddDays(2))

//get a boolean if there is an event tomorrow
bool tomorrowHasEvents = events.Exists(tomorrow.InPeriod);

//get events for tomorrow
List tomorrowEvents = events.FindAll(tomorrow.InPeriod);

//get first event for tomorrow (first item in list!)
DateTime tomorrowFirstEvent = events.Find(tomorrow.InPeriod);
//get last event for tomorrow
DateTime tomorrowLastEvent = events.FindLast(tomorrow.InPeriod);

//get the index of the first event for tomorrow
int tomorrowFirstEventIndex = events.FindIndex(tomorrow.InPeriod);
//get the index of the last event for tomorrow
int tomorrowLastEventIndex = events.FindLastIndex(tomorrow.InPeriod);

//remove all events for tomorrow
int removedItems = events.RemoveAll(tomorrow.InPeriod);

//are all events in the list tomorrow
bool allEventsTomorrow = events.TrueForAll(tomorrow.InPeriod);

}
}

Friday, June 13, 2008

.NET 2.0 = .NET 3.0 = .NET 3.5

Yesterday I had a discussion on an internal Microsoft Developers meeting about the status of .NET 3.5. We had presented that .NET 3.0 is an extension of .NET 2.0, and not a new version. My statement that the status of .NET 3.5 is the same, it is basically .NET 2.0 with extra features, was received sceptically.
Just to prove I'm right, here my observations.

Build a very simple .NET Console application, using two lines of code:

Console.WriteLine("Hello World");
Console.WriteLine("using version: {0}", System.Environment.Version.ToString());


With Visual Studio 2008, you can build this with all three version of the framework. And all three executables yields the same results: using version: 2.0.50727.1433.

ILDASM one of these assemblies gives the same assembly header:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 2:0:0:0
}


Proving all three versions are based on the .NET core version 2.0 (and this is the same version you should configure in ASP.NET. There is no v3 there).
Just to be sure if you want to upgrade to 3.5 at your customer to mention that version 3.5 also is basically .NET 2.0, with some extra features added. I won't say that the libraries of .NET 2.0 are the same with 3.5, but runtime versions are equal.

Rick Strahl blogged about this a while ago.

Friday, May 2, 2008

Unexpected SqlException...

On the production servers at the customer I'm currently working for, we had a strange error regarding a new feature in our reporting tools. A strange error, because during the development and test cycle of our release, we hadn't found any issues regarding SQL errors.

The error firing was 'The count aggregate operation cannot take a uniqueidentifier data type as an argument', during the execution of SELECT COUNT(Item.Id) AS ItemCount ... while the datatype of Item.Id was uniqueidentifier.

The only difference between our development, test and production servers is the version of MS SQL Server. While we migrated our dev and test servers to 2005, production was still behind on version 2000. And version 2000 can't run an aggregate operation on a uniqueidentifier, you need to run it with the asterisk instead (like COUNT(*) ).

Fortunately, migration to MS-SQL 2005 is already scheduled to happen soon :)

Thursday, April 3, 2008

Show your CC.NET dashboard in Sharepoint

I was wondering today if it's possible to get the webdashboard for CruiseControl.NET in Sharepoint. I didn't want to use an html scrapper, so I thought the XML webpart should be a good start. I needed the server status as XML, but found no reference in the helpfiles of CC.Net. On the other hand, Thoughtworks does have a page with information about a xml format for CI build status.
After inspecting the CCTray application and the logfiles on my server, I finally found the undocumented URL for this XML document with the status: http://buildserver.local/XmlServerReport.aspx.
After this quest for XML, I only needed an XSLT to get the results. So here it is:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />

  <xsl:template match="/">

    <table border="0" cellpadding="0" cellspacing="0">

      <thead>

        <th style="text-align:left;">Project</th>

        <th>&#160;</th>

        <th style="text-align:left;">Status</th>

        <th>&#160;</th>

        <th style="text-align:left;">Last buildtime</th>

        <th>&#160;</th>

        <th style="text-align:left;">Buildlabel</th>

        <th>&#160;</th>

        <th style="text-align:left;">Activity</th>

      </thead>

      <tbody>

        <xsl:apply-templates select="/CruiseControl/Projects/Project"/>

      </tbody>

    </table>

  </xsl:template>

 

  <xsl:template match="Project">

    <tr>

      <td class="ms-vb" align="top" nowrap="nowrap">

        <xsl:element name="a">

          <xsl:attribute name="onfocus">OnLink(this)</xsl:attribute>

          <xsl:attribute name="href">

            <xsl:value-of select="@webUrl"/>

          </xsl:attribute>

          <xsl:attribute name="onclick">GoToLink(this);return false;</xsl:attribute>

          <xsl:attribute name="target">_self</xsl:attribute>

          <xsl:value-of select="@name"/>

        </xsl:element>

      </td>

      <td>&#160;</td>

      <xsl:element name="td">

        <xsl:attribute name="class">ms-vb</xsl:attribute>

        <xsl:attribute name="align">top</xsl:attribute>

        <xsl:attribute name="style">

          padding-bottom: 3px;

          <xsl:choose>

            <xsl:when test="@lastBuildStatus='Failed'">

              color:red;

            </xsl:when>

            <xsl:when test="@lastBuildStatus='Exception'">

              color:red;

            </xsl:when>

            <xsl:when test="@lastBuildStatus='Unknown'">

              color:yellow;

            </xsl:when>

            <xsl:when test="@lastBuildStatus='Failed'">

              color:red;

            </xsl:when>

            <xsl:otherwise>

              color:green;

            </xsl:otherwise>

          </xsl:choose>

        </xsl:attribute>

        <xsl:value-of select="@lastBuildStatus"/>

      </xsl:element>

      <td>&#160;</td>

      <td class="ms-vb" style="padding-bottom: 3px;" align="top">

        <xsl:value-of select="substring-before(@lastBuildTime,'T')"/>&#160;

        <xsl:value-of select="substring-before(substring-after(@lastBuildTime,'T'),'.')"/>

      </td>

      <td>&#160;</td>

      <td class="ms-vb" style="padding-bottom: 3px;text-align:right;" align="top">

        <xsl:value-of select="@lastBuildLabel"/>

      </td>

      <td>&#160;</td>

      <xsl:element name="td">

        <xsl:attribute name="class">ms-vb</xsl:attribute>

        <xsl:attribute name="align">top</xsl:attribute>

        <xsl:attribute name="style">

          padding-bottom: 3px;

          <xsl:choose>

            <xsl:when test="@activity='Building'">

              color:red;

            </xsl:when>

            <xsl:when test="@activity='CheckingModifications'">

              color:yellow;

            </xsl:when>

            <xsl:otherwise></xsl:otherwise>

          </xsl:choose>

        </xsl:attribute>

        <xsl:value-of select="@activity"/>

      </xsl:element>

    </tr>

  </xsl:template>

</xsl:stylesheet>

 



Now you need only to configure a custom XML Webpart to load the xml from your buildserver, set the XSLT and the title of the webpart.

Wednesday, March 26, 2008

C# test automation with Internet Explorer

As a follow up on my previous post, I had the idea you can do the same in managed code (in your test library, for instance). Although this won't exactly be a unit test (especialy with the example search form, it's more integration testing), it can be usefull in some scenarios.

You need a reference to two COM dll's,
MSHTML
Microsoft HTML Object Library
SHDocVw
Microsoft Internet Controls


After that, you can use the following example code inside your test (I present it here as one block. Some things can be put in test setup and teardown):

SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorerClass();
object missing = new object();
ie.Navigate("http://localhost/Default.aspx", ref missing, ref missing, ref missing, ref missing);
ie.Visible = true;
while (ie.Busy)
{
System.Threading.Thread.Sleep(500);
}
mshtml.HTMLDocumentClass doc = ie.Document as mshtml.HTMLDocumentClass;
doc.getElementById("searchbox").setAttribute("value", "test", 0);
doc.getElementById("searchsubmit").click();
while (ie.Busy)
{
System.Threading.Thread.Sleep(500);
}
string bodytext = doc.body.innerHTML;
Debug.Assert( bodytext.IndexOf("documents found")>0);

ie.Quit();

PowerShell Web UI test automation

Just read an article in MSDN magazine about test automation for Internet Explorer so you can test your web user interface. There are other tools for this (like Selenium), but those need quite a setup.

Execute a search-box test in PowerShell:

$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("http://localhost/Default.aspx")
$ie.visible = $true
$doc = $ie.document
$doc.getElementByID("searchbox").value = "test"
$doc.getElementByID("searchsubmit").click()

Monday, March 17, 2008

Dutch 'Webrichtlijnen' and binary downloads

The Dutch Web Guidelines (a quality model for sustainable and accessible websites) describe what to do with downloads on your page. This isn't meant for HTML and images, but when you place Adobes Protable Document Format (pdf) or Rich Text Documents (rtf), those documents can be opened in your current window. It is possible to open those files in new windows (although the target="_blank" solution doesn't conform to XHTML validation, some solutions do exist , like rel="external" and JavaScript replacement). But this can be a browser window. Although you can configure your browser, the majority of users don't have the knowledge to tweak their browser to do what they want with these files.
The solution from the Webrichtlijnen:

Do not automatically open links to downloadable files in a new window.


Guideline R-pd.8.22


One way of getting this done is setting the HTTP Content-disposition header
By having the web server send an extra HTTP header for the downloadable file to the browser, the browser can decide whether to download this file untouched as an attachment to the visitor's hard disk.

The best way to do this is writing a custom HTTP Module which can check on served file extensions or MIME Types and add the content disposition header for configured downloads.
In this example implementation, I configure the file extensions in code, but you can always configure this in your config, database or any file.


public class ContentDispositionModule : IHttpModule
{
#region IHttpModule Members

///<summary>
///Initializes the module and prepares it to handle requests.
///</summary>
///<param name="context">An <see cref="T:System.Web.HttpApplication"></see>
///that provides access to the methods, properties, and events common
///to all application objects within an ASP.NET application </param>
public virtual void Init(HttpApplication context)
{
context.PreSendRequestHeaders += new EventHandler(SetContentDispositionHeader);
}

private static void SetContentDispositionHeader(object sender, EventArgs e)
{
string url = ((HttpApplication)sender).Context.Request.Path;
if (IsUrlPatternMatch(url))
{
((HttpApplication)sender).Context.Response.AppendHeader("Content-Disposition", "attachment");
}
}

///<summary>
///Disposes of the resources (other than memory) used by the module that implements
///<see cref="T:System.Web.IHttpModule"></see>.
///</summary>
public virtual void Dispose()
{
}

/// <summary>
/// Check the url against the binaryExtension patterns
/// </summary>
/// <param name="strUrl">url to check</param>
/// <returns>true if it matches the binaryExtension pattern</returns>
private static bool IsUrlPatternMatch(string strUrl)
{
// get this string from a more configurable place.
string binaryExtensions = "*.pdf,*.rtf";
if (!string.IsNullOrEmpty(binaryExtensions))
{
foreach (string extension in binaryExtensions.Split(','))
{
if (!string.IsNullOrEmpty(extension))
{
if (Regex.IsMatch(strUrl, extension.Trim()))
{
// the url path contains the specified regex string, so return true and break out of loop
return true;
}
}
}
}
return false;
}

#endregion
}


After coding this module, you'll need to change the .config so the module will be activated for usage. Add it to the httpModules of the system.web section. You'll also need to configure IIS that all needed extensions are routed through your ASP.NET ISAPI dll.

Friday, March 14, 2008

MCPD - EAD

Yesterday I had my 70-554 exam, and fortunately I passed with 880! It was a hard and difficult exam, so I was really glad to see this number on my screen.
I'm now certified for:
  • Microsoft Certified Technology Specialist: .NET Framework 2.0 Distributed Applications

  • Microsoft Certified Professional Developer: Enterprise Application Developer


Thursday, March 13, 2008

LINQ Design Guidelines

Mircea Trofin is writing on his blog some design guidelines for writing .NET LINQ code. It gives you a quick start to design qualitatively LINQ code.

Thursday, February 28, 2008

Sandcastle Themes

Sandcastle is documentation tool for building MSDN-like help documents. Although it's still in progress, it is already working great. Unfortunately, the documentation is very sparse.

One of the options you can give is the style of the documentation. But I found no description of the styles.
This are screenshots of the 3 different styles:

Hana



VS2005



Prototype


Tuesday, February 19, 2008

CC.Net project unexpected build failure

The last couple of weeks (after migrating to a new build server) I had strange behavior with two web projects building on CruiseControl.NET.
The build project is configured to build after a code check in on subversion. But after the check in, the build fails. A manual 'force build' successfully builds the project.
The build log only said there was an error durring the build, but without a clue what went wrong (and especially when you want to blame project members for checking in bad code ;).

Digging in the ccnet.log I finally found the the cause;

[project-x development:WARN] Process timed out:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe
Process id: 3380. This process will now be killed.


The question is, why can't there be a descriptive error in the build log of the project?
After increasing the seconds in the <tastk><MSBuild><Timeout> element, everything indeeds goes fine.

Friday, February 1, 2008

070-553 down, 070-554 to go

I just passed my 70-553 exam for the upgrade to MCPD:Enterprise Application Developer. So I will need an other exam, but following the 553 exam guide, I now earned two MCTS certification credits:

  • Microsoft Certified Technology Specialist: .NET Framework 2.0 Web Applications

  • Microsoft Certified Technology Specialist: .NET Framework 2.0 Windows Applications


Thursday, January 31, 2008

Lutz Roeder's Reflector

I just stumbled upon a nice Reflector tool for .NET after a tip of a colleague. It already helped with finding a bug in some Tridion .NET dll's...

Share