I remember reading about the MSBuild CodeTaskFactory a couple years ago and hadn't run into a situation where I needed it until now. CodeTaskFactory is a great way to extend MSBuild's capabilities without having to go through the hassle of creating a custom MSBuild Task and having to make sure everyone has the dll.
<UsingTask TaskName="TestWebAppAvailable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup>
<hostname ParameterType="System.String" Required="true" />
<servers ParameterType="System.String[]" Required="true" />
<Result ParameterType="System.String" Output="true" />
<!--<TestSuccess ParameterType="System.Boolean" Output="true" />-->
</ParameterGroup>
<Task>
<!--<Reference Include="System.Xml"/>-->
<Reference Include="System.IO"/>
<Reference Include="System.Net"/>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Using Namespace="System.Net"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
string requestUrl = "http://" + hostname + "/Default.aspx";
Result = "success";
foreach (string server in servers)
{
Log.LogMessage("Server: " + server, MessageImportance.Normal);
if (string.IsNullOrEmpty(server))
{
continue;
}
Log.LogMessage("Warming up: " + requestUrl, MessageImportance.Normal);
System.Net.HttpWebResponse res = null;
try
{
System.Net.WebRequest wr = System.Net.WebRequest.Create(requestUrl);
wr.Timeout = 20000;
wr.Proxy = new System.Net.WebProxy("http://" + server, false);
res = (HttpWebResponse)wr.GetResponse();
Log.LogMessage(server + " - " + res.StatusCode, MessageImportance.Normal);
}
catch (System.Net.WebException ex)
{
res = (HttpWebResponse)ex.Response;
Log.LogMessage("EXCEPTION: " + ex.ToString(), MessageImportance.High);
Log.LogMessage("res == null: " + (res == null).ToString(), MessageImportance.High);
Log.LogMessage("Server: " + server, MessageImportance.High);
Log.LogMessage("res.StatusCode: " + (res != null ? res.StatusCode.ToString() : "Res was null"), MessageImportance.High);
}
catch (System.Exception ex) {
throw;
}
Log.LogMessage("res == null: " + (res == null).ToString(), MessageImportance.High);
if (res.StatusCode != System.Net.HttpStatusCode.OK)
{
string message = server + " Web request failed with code: " + res.StatusCode.ToString();
System.Net.WebException exception = new System.Net.WebException(message);
if (res != null)
{
res.Close();
}
Result = server;
Log.LogMessage("EXCEPTION: " + message, MessageImportance.High);
break;
}
if (res != null)
{
res.Close();
}
}
]]>
</Code>
</Task>
</UsingTask>
Basically this takes in a host header for the hostname and a list of servers. It then iterates over the servers and requests the Default.aspx page. A successful request returns "success". A request that returns a status code that is not 200 returns the server name that failed.
Then using the new custom task is as easy as the following:
<ItemGroup>
<Servers Include="$(DeploymentWebServer1)"></Servers>
<Servers Include="$(DeploymentWebServer2)"></Servers>
</ItemGroup>
<TestWebAppAvailable hostname="$(DeploymentHostname)" servers="@(Servers)" ContinueOnError="True">
<Output TaskParameter="Result" PropertyName="TestResult" />
</TestWebAppAvailable>
<Error Text="Server $(TestResult) returned a bad response. Recopy web application files." Condition="'$(TestResult)' != 'success'" />