Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

NAVIGATION - SEARCH

Presenting at the OpenXML DII workshop Brussels

First things first: WTF is DII??? It's the "Document Interoperability Initiative" that Microsoft launched. The workshop will be a day filled with presentations from a variety of people, including members of the Office product groups at Microsoft and developers and consultants from several other companies (basically like the one held in Redmond a few weeks ago).

Together with Julien Chable, I'll be doing a talk on "Document Interop from an Open Source perspective - PHPExcel and OPENXML4J". Both our open-source products PHPExcel and OPENXML4J will be highlighted with some background and technical demos. We will prove that OpenXML documents provide interoperability between platforms (Windows / Linux) and technologies (.NET, PHP and Java).

Hope to see you there next tuesday!

kick it on DotNetKicks.com

Using the ASP.NET MVC ModelBinder (screencast)

A new screencast has just been uploaded to the MSDN Belgium Chopsticks page. Don't forget to rate the video!

Using ASP.NET MVC ModelBinder

Abstract: "This screencast demonstrates how code can be made more maintainable and testable by delegating binding to client data to the ASP.NET MVC model binder architecture."

kick it on DotNetKicks.com

Partial page updates with ASP.NET MVC and jQuery (and action filters)

When building an ASP.NET MVC application, chances are that you are using master pages. After working on the application for a while, it's time to spice up some views with jQuery and partial updates.

Let's start with an example application which does not have any Ajax / jQuery. Our company's website shows a list of all employees and provides a link to a details page containing a bio for that employee. In the current situation, this link is referring to a custom action method which is rendered on a separate page.

Example application

Spicing things up with jQuery

The company website could be made a little sexier... What about fetching the employee details using an Ajax call and rendering the details in the employee list? Yes, that's actually what classic ASP.NET's UpdatePanel does. Let's do that with jQuery instead.

The employees list is decorated with a CSS class "employees", which I can use to query my DOM using jQuery:

[code:c#]

$(function() {
    $("ul.employees > li > a").each(function(index, element) {
        $(element).click(function(e) {
            $("<div />").load( $(element).attr('href') )
                        .appendTo( $(element).parent() );
            e.preventDefault();
        })
    });
});

[/code]

What's this? Well, the above code instructs jQuery to add some behaviour to all links in a list item from a list decorated with the employees css class. This behaviour is a click() event, which loads the link's href using Ajax and appends it to the list.

Now note there's a small problem... The whole site layout is messed up, because the details page actually renders itself using a master page.

Messed-up employees list after performing an Ajax call

Creating a jQueryPartial action filter

The solution to this broken page is simple. Let's first create a new, empty master page, named "Empty.Master". This master page should have as many content placeholder regions as the original master page, and no other content. For example:

[code:c#]

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Empty.Master.cs" Inherits="jQueryPartialUpdates.Views.Shared.Empty" %>

<asp:ContentPlaceHolder ID="MainContent" runat="server" />

[/code]

We can now apply this master page to the details action method whenever an Ajax call is done. You can implement this behaviour by creating a custom action filter: jQueryPartial.

[code:c#]

public class jQueryPartial : ActionFilterAttribute
{
    public string MasterPage { get; set; }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        // Verify if a XMLHttpRequest is fired.
        // This can be done by checking the X-Requested-With
        // HTTP header.
        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != null
            && filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            ViewResult viewResult = filterContext.Result as ViewResult;
            if (viewResult != null)
            {
                viewResult.MasterName = MasterPage;
            }
        }
    }
}

[/code]

This action filter checks for the precense of the X-Requested-With HTTP header, which is provided by jQuery when firing an asynchronous web request. When the X-Requested-With header is present, the view being rendered is instructed to use the empty master page instead of the original one.

One thing left though: the action filter should be applied to the details action method:

[code:c#]

[jQueryPartial(MasterPage = "Empty")]
public ActionResult Details(int id)
{
    Employee employee =
        Employees.Where(e => e.Id == id).SingleOrDefault();

    ViewData["Title"] = "Details for " +
        employee.LastName + ", " + employee.FirstName;
    return View(employee);
}

[/code]

When running the previous application, everything should render quite nicely now.

Working example

Want the sample code?

You can download the sample code here: jQueryPartialUpdates.zip (134.10 kb)

kick it on DotNetKicks.com

OpenXML support in Zend Framework 1.7 Lucene indexer

image It has indeed been a long time since I blogged about OpenXML. However, this does not mean I'm completely doing nothing with it! PHPExcel still keeps eating a lot of evening hours as well as some other OpenXML-related projects.

The folks at Zend contacted me if I would be interested in implementing OpenXML indexers for the Zend Framework Lucene Indexer. I've blogged about indexing OpenXML files once before, but since today's Zend Framework 1.7 release, indexing OpenXML documents is as easy as indexing any other natively supported file format. Want to know how? Check the documentation in the manual at http://framework.zend.com/manual/en/zend.search.lucene.html.

kick it on DotNetKicks.com

Integrating NUnit test results in Team Build 2008

When using Team Foundation Server 2008 and Team Build, chances are you are developing unit tests in Microsoft’s test framework which is integrated with Visual Studio 2008. This integration offers valuable data hen a build has been finished on the build server: test run results are published in the Team Foundation Server 2008 data warehouse and can be used to create detailed metrics on how your development team is performing and what the quality of the product being developed is.

Not all software development teams are using Microsoft’s test framework. Perhaps your team is using Team Foundation Server 2008 and creates (unit) tests using NUnit. By default, NUnit tests are not executed by the Team Build server nor are they published in the Team Foundation Server 2008 data warehouse. The following guide enables you to leverage the features Team Foundation Server 2008 has to offer regarding metrics, by customizing the build process with the necessary steps to publish test results.

(cross-posted on RealDolmen ALM Blog)

1. Prerequisites

Make sure the following prerequisites are present on your Team Build server (in addition to a default build server installation):

2. Registering NUnit framework in the global assembly cache (GAC)

For NUnit tests to be run in a Team Build script, make sure that the NUnit framework is registered in the global assembly cache (GAC). This can be achieved by copying the file C:\Program Files\NUnit 2.4.8\bin\nunit.framework.dll to C:\Windows\Assembly.

clip_image002

3. Customizing a build script

After installing all prerequisites, make sure you know all paths where these tools are installed before continuing.

The build script for a NUnit enabled build should be modified in several locations. First of all, the MSBuild Community Tasks target file should be referenced. Next, a new build step is added in the AfterCompile hook of the build script. This build step will run the NUnit tests in the compiled DLL’s, transform them to a Microsoft Test results file (*.trx) and publish this transformed file to the Team Foundation Server 2008.

Open the TFSBuild.proj file from source control and merge the following lines in:

[code:xml]

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> 
    <!-- Do not edit this --> 
    <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" /> 
    <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.targets" /> 
    <ProjectExtensions> 
        <!-- ... --> 
    </ProjectExtensions> 

    <!-- At the end of file: --> 

    <ItemGroup> 
        <AdditionalReferencePath Include="$(ProgramFiles)\Nunit 2.4.7\bin\" /> 
    </ItemGroup> 

    <Target Name="AfterCompile"> 
        <!-- Create a Custom Build Step --> 
        <BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)" BuildUri="$(BuildUri)" Name="NUnitTestStep" Message="Running NUnit Tests"> 
            <Output TaskParameter="Id" PropertyName="NUnitStepId" /> 
        </BuildStep> 

        <!-- Get Assemblies to test --> 
        <ItemGroup> 
            <TestAssemblies Include="$(OutDir)\**\Calculator.dll"/> 
        </ItemGroup> 

        <!-- Run NUnit and check the result --> 
        <NUnit ContinueOnError="true" Assemblies="@(TestAssemblies)" OutputXmlFile="$(OutDir)nunit_results.xml" ToolPath="$(ProgramFiles)\Nunit 2.4.8\bin\"> 
            <Output TaskParameter="ExitCode" PropertyName="NUnitResult" /> 
        </NUnit> 
        <BuildStep Condition="'$(NUnitResult)'=='0'" TeamFoundationServerUrl="$(TeamFoundationServerUrl)" BuildUri="$(BuildUri)" Id="$(NUnitStepId)" Status="Succeeded" /> 
        <BuildStep Condition="'$(NUnitResult)'!='0'" TeamFoundationServerUrl="$(TeamFoundationServerUrl)" BuildUri="$(BuildUri)" Id="$(NUnitStepId)" Status="Failed" /> 

        <!-- Regardless of NUnit success/failure merge results into the build --> 
        <Exec Command="&quot;$(ProgramFiles)\nxslt-2.3-bin\nxslt2.exe&quot; &quot;$(OutDir)nunit_results.xml&quot; &quot;$(ProgramFiles)\MSBuild\NUnit\nunit transform.xslt&quot; -o &quot;$(OutDir)nunit_results.trx&quot;"/> 
        <Exec Command="&quot;$(ProgramFiles)\Microsoft Visual Studio 9.0\Common7\IDE\mstest.exe&quot; /publish:$(TeamFoundationServerUrl) /publishbuild:&quot;$(BuildNumber)&quot; /publishresultsfile:&quot;$(OutDir)nunit_results.trx&quot; /teamproject:&quot;$(TeamProject)&quot; /platform:&quot;%(ConfigurationToBuild.PlatformToBuild)&quot; /flavor:&quot;%(ConfigurationToBuild.FlavorToBuild)&quot;" IgnoreExitCode="true" /> 

        <!-- If NUnit failed it's time to error out --> 
        <Error Condition="'$(NUnitResult)'!='0'" Text="Unit Tests Failed" /> 
    </Target>
</Project>

[/code]

4. Viewing test results

When a build containing NUnit tests has succeeded, results of this tests are present in the build log:

clip_image004

When clicking the test results hyperlink, Visual Studio retrieves the result file from Team Foundation Server 2008 and displays it in the test results panel:

clip_image006

kick it on DotNetKicks.com