Book review: MCPD 70-519 Exam Ref: Designing and Developing Web Applications Using Microsoft® .NET Framework 4

I recently completed my MCPD certification for web development and before taking the 70-519 exam I read MCPD 70-519 Exam Ref: Designing and Developing Web Applications Using Microsoft® .NET Framework 4 by Tony Northrup. This blog post is a short review of the book.

Short version
If taking the 70-519 exam, this book is well worth a look as it discusses many development aspects related to the exam. However, it should not be used as general architecture guidance on the Microsoft .Net platform as it’s too narrowly scoped.

Longer version
The book has six chapters:

  1. Designing the Application Architecture
  2. Designing the User Experience
  3. Designing Data Strategies and Structures
  4. Designing Security Architecture and Implementation
  5. Preparing for and Investigating Application Issues
  6. Designing a Deployment Strategy

These chapters cover many design and development aspects you’ll likely come across in a real project but it should be noted that the content is pretty brief and doesn’t go into very much detail. This is in line with the scope of the 70-519 exam which assumes you have the technical know-how to develop solutions and is more geared towards architectural decisions.

Another aspect of the content of the chapters are that they are coloured by the author’s personal opinions, as so often is the case when discussing software architecture. This is probably unavoidable, but I especially noted this in the chapters discussing data access strategies and monitoring/logging. The author discusses the options available in the .Net Framework but doesn’t mention other alternatives such as common open source frameworks (e.g. NHibernate, log4net, etc). This can lead to confusion as some statements, if read literally, are inaccurate. For example, after reading page 90 you might come to the conclusion that WCF Data Services requires using the Entity Framework, which is wrong. (What is required is a class that exposes IQueryable<T> objects.)

This aspect of the book should be kept in mind when reading the book, and then it becomes useful for preparing for the exam. It also serves as a good overview of the technologies available in the .Net Framework as developers. The book is easy to read and not too long, just a little more than 250 pages.

On a personal note, the exam was actually pretty easy so if you’re an experienced developer I shouldn’t do too much studying before taking it. This book serves as an overview if you feel the need to refresh your knowledge but reading it is probably not required to pass the exam.

Final note
I read this book electronically as a PDF on my Android tablet, and if you do the same then I suggest taking some time to research the best PDF-reader app to use as the reading experience is greatly affected by this choice. My choice was ezPDF Reader Lite which allows tweaking the zoom factor and other settings. This is very useful as the aspect ratio of the tablet screen and the printed book are probably not identical.

I also tried using the ePub version but found that in that version too much formatting was lost in tables and other more advanced design elements.

Log file searching using PowerShell

I recently had to do some IIS log file parsing to solve a performance problem and it turned out that PowerShell was a very useful tool for doing this. I thought it might be a good idea to share a few one-liners for the benefit of others (as well as myself the next time I need to do it).

Here we go:

Get-Item *.log | Where-Object { $_.LastWriteTime -gt "2011-09-01" } | Select-String 'foobar'

The above line retrieves a collection of files filtered so that only files with the “.log” extension is matched. It then checks that the last modification time is later than a given date and finally it selects and displays all content lines containing the string “foobar”.

To make it search for files recursively in sub-folder, switch the Get-Item cmdlet for something like Get-ChildItem . -recurse. This can look like this:

Get-ChildItem . -recurse -filter *.log | Select-String 'foobar' | Select-Object -property Path, Line

(Note that is that example we also limit the display to include the properties (file) Path and (matched) Line to make the result easier to read.)

If you want to analyze the results in detail it’s probably a good idea to output the results to a file:

Get-Item *.log | Where-Object { $_.LastWriteTime -gt "2011-09-01" } | Select-String 'foobar' | Add-Content foobarsearchresult.txt

Note that we use the Add-Content cmdlet instead of piping (using the > operator) in order to avoid newlines at the console width position in the file.

To display the number of matched lines in the files (assuming we created several search result files above), we can do things like this:

Get-Item *.txt | % { $_.Name; get-content $_ | measure-object }

The result will be similar to this:

searchresult_foo.txt
Count    : 10
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

searchresult_bar.txt
Count    : 122
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

Apparently we had 10 lines in the ‘searchresult_foo.txt’ file and 122 in ‘searchresult_bar.txt’. This was enough to find my problem (which happened to be an overambitious SharePoint search crawl, but that’s another story…).

Before I stopped, I couldn’t resist creating a slightly prettier line count report:

Get-Item  *.txt | % { Write-Host ("{0,-50} " -f $_.Name) -NoNewLine; get-content $_ | measure-object | % { "{0,10} lines" -f $_.Count } }

The result is now:

searchresult_foo.txt                                       10 lines
searchresult_bar.txt                                      122 lines

Besides giving prettier results, this script also prints the name of each file before actually counting the lines in it. This gives nice feedback to the user when the files are large and the counting takes time.

PowerShell is really becoming an increasingly important tool in my toolbox…

/Emil

Detecting unhandled errors in ASP.Net applications

For my own reference, here’s how to detect unhandled exceptions in Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
  // Log error
  Exception ex = Server.GetLastError().GetBaseException();
  string msg = String.Format("Ohanterat fel!\r\nAdress: {0}\r\nFelmeddelande: {1}", Request.Url, ex.Message);
  LogHelper.Error(msg, ex);

  Server.ClearError();

  // Display simple error page
  Response.Write("Ett oväntat fel har inträffat...\r\n");
  Response.Write("<br/>\r\n<pre>\r\n");
  Response.Write(ex.ToString());
  Response.Write("<br/>\r\n</pre>\r\n");
  Response.End();
}

We mostly do it like this, if you have a better suggestion, please post a comment 🙂

/Emil

log4net configuration examples

Almost every application requires, or at least benefits greatly from, some kind of logging of events and errors. I suspect all of us have written custom code for logging to text files, database tables, the event log and other formats. We all know that we shouldn’t do this since there are several frameworks out there to help us, such as Microsoft’s own Tracing functionality, NLog and log4net. The obstacle to using them is often that it can be difficult to know how to configure them to work properly which is why this post will describe a set of configuration examples for log4net to make that framework do it’s magic.

For those of you new to log4net it’s a really useful package but somewhat difficult to configure, which is what I will try to help with in this post. I will not try to write a tutorial for it since others have already done so. Instead I will show a set of confiuration examples I personally find useful.

To use log4net, you need to add a reference to log4net.dll. Then a new section in the application’s config file must be added:

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

Log4net logging is based on a provider-like design where each type of logging is done in a so called appender. There are appenders for file system files, databases, etc. and it’s in these appenders that log4net’s power lies.

To configure which appenders to use it easiest to use the root configuration element like this:

<log4net>
  ...
  <root>
    <level value="Debug"/>
    <appender-ref ref="ColoredConsoleAppender"/>
    <appender-ref ref="RollingFileAppender"/>
  </root>
</log4net>

We haven’t configured the referenced appenders yet, so that is the next step. The remainder of the post will be about some of the appenders that comes with log4net.

APPENDERS

Colored console appender
This appender is very useful for console applications and enables different types of events (debug, info, error, etc) to be displayed in different colors.

Here’s how to configure it:

    <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
        <level value="ERROR"/>
        <foreColor value="Red, HighIntensity"/>
      </mapping>
      <mapping>
        <level value="INFO"/>
        <foreColor value="White"/>
      </mapping>
      <mapping>
        <level value="DEBUG"/>
        <foreColor value="Green"/>
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%-5level - %message%newline"/>
      </layout>
    </appender>

RollingFileAppender
This appender is used to write to a file while limiting the file size. When the maximum file size is reached then a new file is created which means that no log file will be unmanagably large.

    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="d:\Logs\WorkflowAborter.log"/>
      <rollingStyle value="Size" />
      <appendToFile value="true"/>
      <maximumFileSize value="2000KB"/>
      <maxSizeRollBackups value="5"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %identity %property{log4net:HostName}: %message%newline%exception"/>
      </layout>
    </appender>

The maxSizeRollBackups setting controls how many files will be created before the first one is deleted.

You can control when log4net creates a new file (rolls the file) by setting the rollingStyle attribute. It’s default setting is Composite which combines date and size limitations, whichever occurs first, to decide when a new file is created. The other possible values are Size and Date which are self-explanatory, and Once which creates a new log file for every time the application is executed.

Note however that, for some reason, the maxSizeRollBackups setting does not work when using Composite or Date so the number of files cannot be limited in when using those settings.

NetOutputDebugStringAppender

Logs events using the OutputDebugString Win32 API call whose output is shown in the Visual Studio output window. The appender is also useful in deployed applications since the output is captured by Mark Russinovich’s DebugView tool. (Just remember to enable “Capture Global Win32” setting of DebugView first, or else nothing will be displayed!)

    <appender name="NetOutputDebugStringAppender" type="log4net.Appender.OutputDebugStringAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="Butler: [%t] %-5p - %m%n" />
        <!--<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />-->
      </layout>
    </appender>

NetTraceAppender

This appender logs to the Microsofts standard tracing framework in .Net. In Visual Studio, output is shown in the output window by default and for deployed applications it’s possible to configure the tracing to store events in different destinations. The appender could be useful if parts of an application is using the tracing framework and other parts are using log4net since it makes it possible to channel all events through the same framework (trace) but this is probably not used very often.

A more useful side effect is that many test runners (e.g. nUnit and ReSharper’s built-in test runner) captures trace calls and stores them with the test result making test failure analysis much easier.

Screen shot of ReSharper with log4net trace output

Configuration:

    <!-- Logga till .Net trace-listeners, t.ex- Outputfönstret i Visual Studio...-->
    <!-- Hamnar i output-fönstret om körs i VS, kan annars visas i DebugView -->
    <appender name="NetTraceAppender" type="log4net.Appender.TraceAppender, log4net">
      <layout type="log4net.Layout.PatternLayout,log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
      </layout>
    </appender>

SmtpAppender
This appender is often overlooked, I have at least not seen many references to using it. It’s very useful for sending mail when an error occurs:

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
  <to value="foo@foobar.se, bar@foobar.se" />
  <from value="helpdesk@foobar.se" />
  <subject value="Error occured in MyApp" />
  <smtpHost value="smtp.foobar.se" />
  <bufferSize value="512" />
  <lossy value="true" />
  <evaluator type="log4net.Core.LevelEvaluator">
  	<threshold value="WARN"/>
  </evaluator>
  <layout type="log4net.Layout.PatternLayout">
  	<conversionPattern value="%n%d %-5level [%t] - %m" />
  </layout>
</appender>

Using configuration similar to the above, a mail such as the following is sent when a WARN or ERROR log occurs:

2011-02-04 03:00:06,958 INFO  [1] - ###############################################
2011-02-04 03:00:07,328 INFO  [1] - Startar...
2011-02-04 03:00:07,362 INFO  [1] - ###############################################
2011-02-04 03:00:07,429 INFO  [1] - Läser upp kursdeltagare 
2011-02-04 03:00:31,265 INFO  [1] - 6437 ska bearbetas.
2011-02-04 03:21:17,153 INFO  [1] - Timmar per vecka omräknade
2011-02-04 03:21:17,263 INFO  [1] - Tidsåtgång timmar per vecka: 00:21:09
2011-02-04 03:21:17,278 INFO  [1] - ----------------------------------------------------------------------------
2011-02-04 03:21:17,479 INFO  [1] - Läser upp kursdeltagare 
2011-02-04 03:22:08,793 INFO  [1] - 26532 ska bearbetas.
2011-02-04 04:10:28,050 ERROR [1] - Kunde inte ändra preliminärt slutdatum för timpott för sfi kd 24085 (Butler kd 83237)

Note that the 10 events prior to the ERROR event that triggered the mail is also included which makes error analysis very much easier.

MemoryAppender
This appender is useful for automated tests.

<appender name="unitTestMemoryAppender" type="log4net.Appender.MemoryAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %identity %property{log4net:HostName} %logger: %message%newline%exception"/>
  </layout>
</appender>

To create unit tests that checks whether logging is performed correctly, code such as this can be used:


using ActiveSolution.Lernia.Utils.Logging;
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Repository.Hierarchy;
using NUnit.Framework;

namespace UtilsTests
{
    [TestFixture]
    public class LoggingTests
    {
        [SetUp]
        public void SetUp()
        {
            var appender = GetAppender();
            if (appender != null)   // Appender kommer vara null om inet loggats ännu.
            {
                appender.Clear();
            }
        }

        [Test]
        public void Logger_ErrorFormat_WithException_ShouldLogMessage()
        {
            // Arrange -----------------------------
            var ex = new ArgumentNullException("foo");

            // Act ---------------------------------
            LogHelper.ErrorFormat(ex, "Oväntat fel för id = {0}", 42);    // Call custom wrapper function for log4net

            // Assert ------------------------------
            var loggedEvents = GetLoggedEvents();
            Assert.That(loggedEvents.Length, Is.EqualTo(1));
            Assert.That(loggedEvents[0].RenderedMessage, Contains.Substring("Oväntat fel för id = 42"));
            Assert.That(loggedEvents[0].RenderedMessage, Contains.Substring("Value cannot be null"));
            Assert.That(loggedEvents[0].RenderedMessage, Contains.Substring("Parameter name: foo"));
        }

        private static LoggingEvent[] GetLoggedEvents()
        {
            MemoryAppender ma = GetAppender();
            return ma.GetEvents();
        }

        private static MemoryAppender GetAppender()
        {
            var h = LogManager.GetRepository() as Hierarchy;
            return h.Root.GetAppender("unitTestMemoryAppender") as MemoryAppender;
        }
    }
}

AdoAppender

The AdoAppender is used to store events in a database. Here’s a configuration example for using a stored procedure to store the events:

<appender name="ErrorHandlerAppender" type="log4net.Appender.AdoNetAppender">
  <filter type="log4net.Filter.LevelRangeFilter">
    <param name="LevelMin" value="WARN" />
  </filter>

  <bufferSize value="1" />
  <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <connectionString value="Data Source=XXXXXXXXX;Initial Catalog=Errorhand;User ID=XXX;Password=XXX" />
  <commandType value="StoredProcedure" />
  <commandText value="ap_errorhandler_ins" />

  <parameter>
    <parameterName value="@APPLICATIONID" />
    <dbType value="String" />
    <size value="16"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="Butler.EducationSI" />
    </layout>
  </parameter>

  <parameter>
    <parameterName value="@USERID" />
    <dbType value="String" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%identity" />
    </layout>
  </parameter>

  <parameter>
    <parameterName value="@SEVERITY" />
    <dbType value="String" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%level" />
    </layout>
  </parameter>

  <parameter>
    <parameterName value="@DESCRIPTION" />
    <dbType value="String" />
    <size value="4000"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%message%newline%exception" />
    </layout>
  </parameter>

  <parameter>
    <parameterName value="@LOCAL_ADDR" />
    <dbType value="String" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{log4net:HostName}" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@REMOTE_ADDR" />
    <dbType value="String" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{log4net:HostName}" />
    </layout>
  </parameter>
</appender>

The configuration segment for AdoAppenders tend to be rather long but the example is fairly self explaining. For more so called “conversionPattern fields” to use in parameters, look here. These are the same fields used in the other appenders to format the log strings. There’s quite a lot of interesting data that can be retrieved so make sure to have a look at the list.

FILTERING

Another powerful feature of log4net is the possibility of filtering. For example, if you’re referencing a 3rd party assembly such as NHibernate.dll that logs its events using log4net then those events can be configured separately like this:

<logger name="NHibernate">
  <level value="Error" />
</logger>

This tells log4net that DEBUG and INFO events from NHibernate should be ignored. The logger name is a string with the start of the logger names the filter should match. Other loggers can be configured in the same way and loggers that aren’t configured fall back to the root logger we defined in the beginning of this post.

TROUBLESHOOTING

Q: What do you do when having trouble with log4net logging?
A: You enable internal logging!

<appSettings>
  <add key="log4net.Internal.Debug" value="true"/>
</appSettings>

Note that these events are logged using the System.Diagnostics.Trace system so that may have to be configured as well. For more info about internal logging, see here.

That’s all for now. I’ll keep updating this post when I find more interesting settings.

/Emil

Assembly version redirection

Here’s how to redirect an assembly reference from one version (or version interval) to another:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="log4net" publicKeyToken="b32731d11ce58905" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="1.2.10.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Note that for this to work, put it as early in your config file as possible since it must occur before the assemblies are referenced. Also note that both the new and old version of the assembly must have the same public key token, if they don’t you’ll get a System.IO.FileNotFoundException during binding.

/Emil

Storing and retrieving strings in the SQL Server session context

Sometimes it can be useful to store temporary data (e.g. a string with the current username for auditing or similar) in the context of the current Sql Server session and it’s actually rather easy to do. All that’s needed is to convert the data to a varbinary of max length 128 and then call SET CONTEXT_INFO like this:

-- store data
DECLARE @encodedUsername AS VARBINARY(128)
SET @encodedUsername = convert(varbinary(128),'emila')
SET CONTEXT_INFO @encodedUsername

Unfortunately it’s not quite as easy to retrieve the original string… You can retrieve the varbinary data using CONTEXT_INFO(), but that will only give the varbinary data back:

SELECT CONTEXT_INFO()

0x656D696C610000000000000...

Converting that data back to a varchar seems to work at first but the string contains trailing 0-characters (cf. CHAR(0) ):

-- Convert to a string, looks ok...
SELECT CONVERT(VARCHAR(MAX), CONTEXT_INFO())
emila

-- ... but the length is 128 characters
SELECT LEN(CONVERT(VARCHAR(MAX), CONTEXT_INFO()))
128

Removing those illegal character is surprisingly difficult (e.g. REPLACE() cannot be used) but one possible solution is to do a conversion into an Xml string:

-- convert to xml for 
SELECT CONVERT(VARCHAR(MAX), (SELECT CONVERT(VARCHAR(MAX), CONTEXT_INFO()) AS data FOR XML PATH('')))
<data>emila&#x00;&#x00;&#x00;&#x00;&#x00;&#x00;&#x00;...

Substrings of that Xml string can then be replaced like in any other string and that logic is best put in a user-defined function:

-- Retrieve data from the context and cleanup illegal characters
CREATE FUNCTION GetLoggedInUserName() RETURNS varchar(20)
AS
  BEGIN
    RETURN
      REPLACE(
        REPLACE(
          REPLACE(
            CONVERT(VARCHAR(MAX), (SELECT CONVERT(VARCHAR(MAX), CONTEXT_INFO()) AS data FOR XML PATH('')))
            , '</data><data>', '')
          , '</data>', '')
        , '&#x00;', '')
  END
GO


SELECT dbo.GetLoggedInUserName()
emila

The result is now a string of the correct length and without illegal characters.

This code works as expected, but perhaps there is a more efficient alternative out there? Please leave a comment if you have a suggestion for improvement 🙂

/Emil

Retrieving domain information in Powershell

Here’s how to retrieve the current domain:

[reflection.assembly]::loadwithpartialname("System.DirectoryServices")
[System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain()

The result is a System.DirectoryServices.ActiveDirectory.Domain object:

Forest                  : i.activesolution.se
DomainControllers       : {ACTIVESERVER101.i.activesolution.se, ACTIVESERVER102.i.activesolution.se}
Children                : {}
DomainMode              : Windows2008R2Domain
Parent                  :
PdcRoleOwner            : ACTIVESERVER102.i.activesolution.se
RidRoleOwner            : ACTIVESERVER102.i.activesolution.se
InfrastructureRoleOwner : ACTIVESERVER102.i.activesolution.se
Name                    : i.activesolution.se

/Emil

Changing a solicit-response BizTalk send port into a one-way port

Sometimes you might have the need to change the type of an existing send port in BizTalk, e.g. from solicit-response to one-way. For example, when consuming a Wcf service using “Add generated items”, the binding files that are generated are for solicit-response send ports requiring you to handle the responses. If you don’t, you get the following error which is very unexpected if you’re not prepared:

The published message could not be routed because no subscribers were found. This error occurs if the subscribing orchestration or send port has not been enlisted, or if some of the message properties necessary for subscription evaluation have not been promoted. Please use the Biztalk Administration console to troubleshoot this failure.

What the message says is that we have no subscriber to the response message of the Wcf request, and in many cases (one-way messages) we’re not interested in supplying one.

Modifying the send port to a one-way send port solves the problem, but as there’s no option for doing that in the BizTalk Administration Console we have to rely on a trick:

  1. export the bindings to file
  2. modify the file
  3. import the file back

Look here for the details, directly from the horse’s mouth (Microsoft):

http://msdn.microsoft.com/en-us/library/cc185524(v=bts.10).aspx

In case that link doesn’t work when you read this post (it’s been known to happen ;-)), here are the required modifications:

  1. Find the relevant SendPort in the binding file and change the value of IsTwoWay property to false.
    <SendPort Name="port_name" IsStatic="true" IsTwoWay="false" BindingOption="0">
  2. Comment out the ReceivePipeline and ReceivePipelineData elements inside the SendPort element.

That’s all. Importing the binding file back into BizTalk Administration Console should update the send port. If it doesn’t, try to delete the old port before importing the binding file.

In all, the above procedure is not all that complicated which makes you wonder why there is no option to do this directly in the administration console, doesn’t it? 🙂

/Emil

Refreshing data in jQuery DataTables

Allan Jardine’s DataTables is a very powerful and slick jQuery plugin for displaying tabular data. It has many features and can do most of what you might want. One thing that’s curiously difficult though, is how to refresh the contents in a simple way, so I for my own reference, and possibly for the benefit of others as well, here’s a complete example of one way if doing this:

<table id="HelpdeskOverview">
  <thead>
    <tr>
      <th>Ärende</th>
      <th>Rapporterad</th>
      <th>Syst/Utr/Appl</th>
      <th>Prio</th>
      <th>Rubrik</th>
      <th>Status</th>
      <th>Ägare</th>
    </tr>
  </thead>
  <tbody> 
  </tbody> 
</table>
function InitOverviewDataTable() {
    oOverviewTable = $('#HelpdeskOverview').dataTable(
        {
            bPaginate: true,
            bJQueryUI: true, // ThemeRoller-stöd
            bLengthChange: false,
            bFilter: false,
            bSort: false,
            bInfo: true,
            bAutoWidth: true,
            bProcessing: true,
            iDisplayLength: 10,
            sAjaxSource: '/Helpdesk/ActiveCases/noacceptancetest',
            fnRowCallback: formatRow
        });
}
function RefreshTable(tableId, urlData) {
    //oSettings.sAjaxSource?
    $.getJSON(urlData,
        null, function (json) {
            table = $(tableId).dataTable();
            oSettings = table.fnSettings();

            table.fnClearTable(this);
            for (var i = 0; i < json.aaData.length; i++) {
                table.oApi._fnAddData(oSettings, json.aaData[i]);
            }
            oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
            table.fnDraw();
        });
}
function AutoReload() {
    RefreshTable('#HelpdeskOverview', '/Helpdesk/ActiveCases/noacceptancetest');

    setTimeout(function () { AutoReload(); }, 30000);
}
$(document).ready(function () {
    InitOverviewDataTable();
    setTimeout(function () {
           AutoReload();
        },
        30000);
});

Property promotion when debatching messages from the BizTalk WCF SQL adapter

Richard Seroter has a great post about how to debatch inbound messages from the WCF SQL adapter in BizTalk 2009/2010: http://seroter.wordpress.com/2010/04/08/debatching-inbound-messages-from-biztalk-wcf-sql-adapter/

The problem is that when polling a database table for new data, we get a single message containing all matching rows. In most cases you probably want to debatch this message into separate message, one for each row, and it’s actually rather easy (see Richard’s post for the details).

There seems to be one problem though, namely that property promotions in the incoming schema (which is created automatically if you’re using typed polling) doesn’t work. One solution for that is to create a separate intermediate schema with the required promotions and transform the incoming messages into that schema using the “inbound maps” setting on the receive port. Note that the map’s source schema should be the top TypedPollingResultSet0 element of the generated schema, not the one below the TypedPolling element, since the transformation is done after debatching takes place.

As an added bonus you don’t mess up your message flows with “TypedPollingResultSet0” message types, that are rather non-descriptive. A message type name of “RaindanceNotification” (or whatever you name the intermediate schema) is much more communicative.

/Emil