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.

Wednesday, February 6, 2008

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...

Tuesday, December 11, 2007

OnInit not firing on controls with default property

Just build some nested controls to run on the web site, but there was some strange stuff going on.
The render method worked fine, but there weren't some values on those controls. The cause of this was that the OnInit, and the OnLoad event's weren't firing.
After some debugging and analyzing the control tree in /trace.axd, I saw there were no controls in the main control.
The reason? I'd put a [ParseChildren(ChildrenAsProperties = true,
DefaultProperty = "Groups")]
attibute on the main control, and all those controls were added to a List collection, but not to the Control collection. So ASP.net didn't took up those child controls for inclusion in the control tree.

A dirty line in the main control OnInit fixed this:
foreach (Group group in Groups) { Controls.Add(group); }.

Wednesday, November 28, 2007

.Net documentation missing

Just figured out that the HtmlWriter.AddAttribute() does an encoding based on the HtmlTextWriterAttribute enum you give as the first parameter. How? By inspecting the source code of Mono. With this knowledge I searched MSDN, but couldn't find a thing.

The bottomline: don't use a writer.AddAttribute(HtmlTextWriterAttribute.Href,
HttpUtility.HtmlAttributeEncode(url));
because then you're encoding twice.

The list of attributes which enode is:

HtmlTextWriterAttribute.Accesskey;
HtmlTextWriterAttribute.Alt;
HtmlTextWriterAttribute.Background;
HtmlTextWriterAttribute.Class;
HtmlTextWriterAttribute.Href;
HtmlTextWriterAttribute.Onchange;
HtmlTextWriterAttribute.Onclick;
HtmlTextWriterAttribute.Src;
HtmlTextWriterAttribute.Title;
HtmlTextWriterAttribute.Value;

Monday, November 12, 2007

PowerShell Shutdown COM+

To shutdown a COM+ object, so you can redeploy the binaries it uses, I had a VBS script to do it. I wondered how I could do it in PowerShell, but lacked time to do so. I just stumbled upon some code to do it, though.

The old script was:

Dim oCatalog ' As COMAdmin.COMAdminCatalog
Dim sName 'As String
Dim sMachine 'As String
Set oCatalog = CreateObject("COMAdmin.COMAdminCatalog")
sName = "Tridion Content Manager"
sMachine = "tridionserver"

oCatalog.Connect sMachine
oCatalog.ShutdownApplication sName



And this became:


$TridionAppName = "Tridion Content Manager"
$TridionMachine = "tridionserver"

$comAdmin = New-Object -comobject COMAdmin.COMAdminCatalog
$comAdmin.Connect($TridionMachine)
$comAdmin.ShutdownApplication($TridionAppName)


(Just leave the line with the call to connect out to run this on your local machine).

Saturday, November 3, 2007

Take screenshots of web pages with FireShot!

Take screenshots of web pages with FireShot!
Works with Firefox, and can grab a bitmap of the whole page (and not only from the visible area).
Very handy while debugging the design for your website (and since I'm currently implementing a css design while communicating the bugs back to the CSS designer), this tool can save some time annotating and merging bitmaps.

Friday, November 2, 2007

VS: Copy Sourcecode as Html

Although I've a javascript on this blog running to highlight code, this solution might be a lot easier.

Monday, October 29, 2007

XSS detection tool for VS2005

Microsoft download has now a tool to detect XSS leaks in ASP.NET code.

XSSDetect is a static code analysis tool that helps identify Cross-Site Scripting security flaws found within Web applications. It is able to scan compiled managed assemblies (C#, Visual Basic .NET, J#) and analyze dataflow paths from sources of user-controlled input to vulnerable outputs. It also detects whether proper encoding or filtering has been applied to the data and will ignore such "sanitized" paths.

Friday, October 26, 2007

VS 2005 Tortoise Integration

For Visual Studio 2005, settings to work with TortoiseSVN within the GUI:

VS 2005 Tortoise Integration.

Thursday, August 2, 2007

Into .Net 3.5

Last week, Microsoft released Beta 2 of VS 2008 (Orcas) with the .NET framework version 3.5. It is released with a go live license, so you can assume it's feature complete now.
There are some small bugs though, but nevertheless it is a good piece of software to work with.

Linq and Lambda functions
A great new feature is linq, and playing with some thoughts and digging up the old Sequoia View I decided to build a proof of concept of this program in .NET 3.5.

The first step is to assemble a collection of files and directories from a drive. Linq and Lambda queries works quite straightforward here; after filling a large list with a custom FileSystemEntry class, it's quite easy to get data from this list.
In the old days, getting a List entry with a specific property value needed a lot of coding. With the net .NET it's like this:

List<FileSystemEntry> list = GetList();
FileSystemEntry testId =
list.First(listEntry => listEntry.Id == "test");


Or just some plain linq to retrieve some entries form the list in a new smaller list:


List<FileSystemEntry> list = GetList();
var entries = from entry
in list
where entry.ParentId == "test"
select entry;
List<FileSystemEntry> childEntries = entries.ToList();


So basically, you can build with this two code blocks a Parent and a Children property on your class, given a List of objects where you can save your object Id and ParentId. Quite easy and straightforward to use.

In a next post, I will cover building a TreeMap of your disc with XAML and WPF.

Thursday, July 19, 2007

Firefox extensions

Maybe is CookieSafe the perfect solution for cookie management?
And Firebug is far better then the webdev toolbar.