Automate Build for a ClickOnce Application Hosted on CodePlex using MSBuild

October 22, 2008 08:51 by merill

This is what I wanted my automated build to do:

  1. Get the latest version from CodePlex
  2. Update the version number in AssemblyInfo.cs
  3. Build the project
  4. Check-in the updated AssemblyInfo.cs
  5. Label the project with the version number
  6. Publish the ClickOnce package to my webserver

In order to achieve this I used the CodePlex Source Control Client (cpc.exe) to perform the get latest and check-ins. I was not able to complete #5 as the cpc client does not provide labelling. Maybe once the SvnBridge supports it I can upgrade this guide to use a SubVersion client.

I also wrote a command line utility SetVersion.exe utility that updates the version number on an AsssemblyInfo.cs or .vb file. The source for this is published as SetVersion on the MSDN Code Gallery.

So without further ado this is the MSBuild project file that performs the tasks.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
  <PropertyGroup>
    <CodePlexProjectName>mycodeplexprojectname</CodePlexProjectName>
    <Version>1.$(CCNetNumericLabel).0.0</Version>
    <BuildFolder>C:\MyBuilds\$(Version)\</BuildFolder>
    <IISPublishFolder>C:\MyInstallLocation\</IISPublishFolder>
    <ProjectFolder>MySolution\Client\</ProjectFolder>
    <BuildPublishFolder>$(ProjectFolder)bin\Release\app.publish</BuildPublishFolder>
    <BuildProject>$(ProjectFolder)Client.vbproj</BuildProject>
    <ToolsFolder>C:\Projects\SolutionFolder\Build\</ToolsFolder>
    <CodePlexClient>$(ToolsFolder)cpc.exe</CodePlexClient>
    <SetVersion>$(ToolsFolder)SetVersion.exe</SetVersion>
    <CodePlexUser>codeplexusername</CodePlexUser>
    <CodePlexPassword>codeplexpassword</CodePlexPassword>
  </PropertyGroup>
 
  <Target Name="Build">
    <Message Text="##Building version: $(Version)" Importance="high"/>
    <Message Text="##Cleaning folder..." Importance="high"/>
    <Exec Command="md $(BuildFolder)"/>
 
    <Message Text="##Getting latest version" Importance="high"/>
    <Exec Command="$(CodePlexClient) checkout $(CodePlexProjectName)" WorkingDirectory="$(BuildFolder)"/>
 
    <Message Text="##Updating build number $(SetVersion) $(BuildFolder)$(ProjectFolder)AssemblyVersionInfo.vb $(Version)" Importance="high"/>
    <Exec Command="$(SetVersion) $(BuildFolder)$(ProjectFolder)AssemblyVersionInfo.vb $(Version)"/>
 
    <Message Text="##Building" Importance="high"/>
    <MSBuild Projects="$(BuildFolder)$(BuildProject)" Targets="Publish" Properties="Configuration=Release;ApplicationVersion=$(Version)" />
 
    <Message Text="##Commiting version change" Importance="high"/>
    <Exec Command="$(CodePlexClient) commit /username $(CodePlexUser) /password $(CodePlexPassword) /message ---Automated-Build---$(Version)" WorkingDirectory="$(BuildFolder)"/>
 
    <Message Text="##Publishing" Importance="high"/>
    <Exec Command="rd $(IISPublishFolder) /s /q"/>
    <Exec Command="xcopy $(BuildFolder)$(BuildPublishFolder)\*.* $(IISPublishFolder) /e /i /y"/>
    <Exec Command="xcopy $(IISPublishFolder)..\default.htm $(IISPublishFolder)"/>
  </Target>
</Project>

Although I’ve worked with MSBuild files in the past this was the very first time I wrote one so a few things to remember. Items defined in the <PropertGroup> node are like declaring variables. You can then use them anywhere in your script in this format $(VariableName).

What's even better is that you can override the default values you provide in the build file with values from the command line like. For example to force a particular version number I can peform the build like this:

MSBuild ReleaseBuild.proj /p:Version=1.6.0.0

When getting the latest version I opted to create a new folder for each build and pull the files into that folder. This way I didn’t have to worry about cleaning the bin folders. Every new build would start from an empty folder.

In my case rather than building the solution file I opted to build just the Client project since that would compile all the dependant projects. The key part that helped me create the necessary files for the ClickOnce publishing was the Targets=”Publish” parameter, that along with the ability to set the ClickOnce version using the properties provided an elegant solution for the tricky problem of keeping the AssemblyVersion and the ClickOnce application version in sync.

<MSBuild Projects="$(BuildFolder)$(BuildProject)" Targets="Publish" Properties="Configuration=Release;ApplicationVersion=$(Version)" />

I use CruiseControl to kick off the build process as well as drive the version numbering. CruiseControl is not absolutely necessary though, as the build file can be run from the command line, as long as a version number is specified.

I’ve packaged the build file along with the SetVersion.exe, cpc.exe (codeplex client) and the ccnet.config for download here.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

WCF Performance Optimization Tips

October 17, 2008 10:48 by merill

I wound up work on my last project and thought of sharing some performance challenges we faced when the product went live.

Keep in mind though that optimization options heavily rely on your application design and its usage scenarios.

Usage Scenario

The usage scenario for which the following optimizations worked are as follows. The WCF services are hosted under IIS and currently only serve requests that come from the desktop client application through the intranet. Roughly 300 instances of the client application will be used concurrently.


Long running calls
The application design used the BackgroundWorker when making calls to the server but the actual WCF call was synchronous. Synchronous calls work well in most scenarios but when your service performs a long running task (>1 sec) it blocks other clients from connecting to the server. Asynchronous calls make better sense in this scenario.
Ref: Synchronous and Asynchronous Operations

Bindings
When designing your application pick the binding carefully as this also affects performance. The WCF services were initially designed to use WSHttpBinding. This binding though affects performance especially when options such as security, reliable sessions and transaction flow are enabled.

As part of the performance tuning we switched to using BasicHttpBinding as none of the WS features were actually being used by the application. This dramatically improved performance because we cut down on all the acknowledgements.

 

Default WSHttpBinding
with Reliable Session Enabled (9 messages)
BasicHttpBinding (2 messages)
WsHttpBinding-Messages BasicBinding-Messages

  

The security we lost when switching over to BasicHttpBinding will be enforced at the network level by locking down the machines that are allowed to make calls to the service.

In our case we could have squeezed out more performance if we had used NetTcpBinding but that would have required IIS7 and WAS.

Ref:
-    WCF Binding Comparison
-    BasicHttpBinding compared to WSHttpBinding at SOAP packet level [Note: Although this author recommends WS over Basic, Microsoft specifies that the secure and reliable sessions be disabled for Load Balanced environments which basically brings it down to Basic].
-    Load Balancing

Service Model Throttling
The service throttling parameters are another key element to look at when performance tuning services. The name is a little misleading though as it tends to imply that you want to throttle your service when in fact these are the default settings that the Microsoft engineers have put in place to prevent DOS attacks against your service.

In our case due to the nature of our application usage these settings caused the server to queue new requests once the default throttling levels of 10 concurrent sessions were reached. What effectively happened was that once long running queries were being processed other requests started getting queued up even though the server memory and processor usage were very low.

The resolution for this was to increase the default values for these settings (shown below) to a few thousand.

<behaviors> 
  <serviceBehaviors> 
    <behavior name="DefaultThrottlingBehavior"> 
      <serviceThrottling maxConcurrentCalls="16" 
                         maxConcurrentSessions="10" 
                         maxConcurrentInstances="[Int32.MaxValue]" /> 
    </behavior> 
  </serviceBehaviors> 
</behaviors> 


Ref:
-    <serviceThrottling>
-    Using ServiceThrottlingBehavior to Control WCF Service Performance

General guidelines when tuning performance

Benchmarks
When tasked with tuning for performance the first requirement is to establish benchmarks on the current service levels and the expected service level once the tuning is completed.

Identify the bottleneck
The next key point is to identify the area that is causing the bottleneck. For the WCF services we tracked the time taken on the client side against the actual execution of the web service to eliminate the network being the bottleneck.
We worked backwards from the database call to ensure that they completed within the specified time.

Having your application instrumented is a key part of the initial design. The Enterprise Library provides instrumentation and open source tools such as log4net are lightweight and effective as well.

Replicate in your dev environment
Effectively testing out any tuning options can only be done if you can repro the issue in your development environment. The built-in load tester in Visual Studio will be a key part of your load testing armoury.

Code Profiling
If the bottleneck points to your code, code profiling tools will help your isolate the problem areas. At the time of this writing Red Gate ANTS Profiler and JetBrains dotTrace are capable solutions. The code profiler built into Visual Studio 2008 is not as effective as these tools.

Finally a shout-out to WCF MVP Buddhike who saved my day by quickly pointing me towards the binding and security modes as the perf culprits.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Silverlight

October 15, 2008 14:46 by merill

Silverlight  2.0 just went live. If you are a .NET developer building ASP.NET or WinForms/WPF applications this is a HUGE deal. Your .NET code can now run within a browser and across platforms (including Mac and on Linux using Moonlight) without requiring the .NET framework installed.

I have never spent much time learning AJAX but I see XAML/WPF basing used heavily in the future. When Silverlight 1.0 was first released I was excited at the prospect of re-using WPF knowledge to build web applications but was sorely disappointed with the lack of tooling and controls. Fast forward today and you have rich tooling support in Visual Studio a number of control (including a grid view and date picker) plus more controls being released by the Client Controls team.

Start learning Silverlight today your going to need it soon. Goodbye AJAX I will avoid you whenever I can.

To get started on Silverlight see the great ScottGu.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

WCF Add Service Reference gotcha with Windows Server

April 18, 2008 09:11 by merill

We recently switched from developing in Vista to Windows Server 2003. Someone had the bright idea that we should develop in the same environment the application is going to be hosted on. Go figure.

What that meant is that you run into wierd issues like this one. When trying to add a Service Reference to a WCF service hosted under IIS you keep getting this 'Add Service Reference Error':

Metadata contains a reference that cannot be resolved: 'http://merill/Services.Host/ClientProfile.svc?wsdl'.
The WSDL document contains links that could not be resolved.
There was an error downloading 'http://merill/Services.Host/ClientProfile.svc?xsd=xsd0'.
The underlying connection was closed: An unexpected error occurred on a receive.
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
An existing connection was forcibly closed by the remote host
Metadata contains a reference that cannot be resolved: 'http://localhost/Services.Host/ClientProfile.svc'.
Metadata contains a reference that cannot be resolved: 'http://localhost/Services.Host/ClientProfile.svc'.
If the service is defined in the current solution, try building the solution and adding the service reference again.

The key part of this message is the reference to the downloading of the xsd. When I tried accessing the .svc url in a browser it worked fine, but trying to access the .svc?xsd=xsd0 brings up the generic 'cannot display webpage' message.

When you unleash your weapon (Process Monitor) on the csc.exe process (this is the compiler generating the xsd) you'll realise that the IIS identity IIS_WPG does not have access to the Windows\Temp folder. Give enough rights to the folder and viola problemo solved.

Happy WCF programming on Windows Server!


Currently rated 3.7 by 6 people

  • Currently 3.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Making use of the '??' operator in C#

February 18, 2008 04:40 by merill

The ?? operator was introduced to C# in 2.0 and I made a mental note to myself to use it when possible.

Recently I had to do some tinkering with good ole Request.Form and Request.QueryString and I kept trying get the neurons to connect and figure out the shorter way of doing it. I knew there was another way to do it than write all this.

   1: string filter = Request.QueryString["Filter"];
   2: if (filter == null)
   3: {
   4:     filter = "";
   5: }

And Google is no help when you have no keyword to search. This is when ReSharper came in handy and prompted to replace the above code with this succinct version.

   1: filter = Request.QueryString["Filter"] ?? "";

BTW: If you are coding in VS 2008 check out the ReSharper 4.0 nightly builds, it's awesome.


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

No color coding for Classic ASP in Visual Studio 2008

December 31, 2007 18:35 by admin

This seems to be a bummer. Color coding and intellisense for VBScript code in Classic ASP pages have been deprecated in VS 2008.

There is a workaround for making it work for files with the .vbs extension but no solution for .asp pages. Hopefully someone would come up with a hack to get it working again.

Until then Microsoft's answer is for us to use VS 2005 or Visual Web Developer 2005. But don't install VWD if you already have VS 2008 installed since VWD will take over all file associations leaving 2008 broken.

You can let Microsoft know how much this sucks by ranting here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=290845


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Moq: Linq to Mock

December 19, 2007 15:29 by admin

Daniel Cazzulino just announced the birth of Moq, now this is mocking done right.

 

// ShouldExpectCallWithArgument
var mock = new Mock<IFoo>();

mock
.Expect(x => x.DoInt(1)).Returns(11);
mock
.Expect(x => x.DoInt(2)).Returns(22);

Assert.AreEqual(11, mock.Instance.DoInt(1));
Assert.AreEqual(22, mock.Instance.DoInt(2));

 

Lambda is starting to make my mouth water.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

The Dangers of Static Events In User Controls

December 18, 2007 14:18 by admin

Static events in user controls can lead to all sorts of weird behavior in your application. Especially when they are hosted in forms that are loaded and unloaded during the lifetime of your application.

public partial class FlexiAddress : UserControl
{
    public static event EventHandler<AddressChangedEventArgs> EventAddressChanged; 

The danger here is that unless you unhook from the static event before your form closes what happens is that although the form is not visible it still hangs around in memory until your application exits.

So if you are showing the form by creating a new instance, every form that is created is loaded into memory and will actually cause a memory leak.

If you want to prove this to yourself the easiest way is to include a Debug.WriteLine in the even handler and then after you've opened and closed the hosting form a couple of times try to do an action that causes the event to be fired. You'll notice that the Output window has one line for each instance of the form that is loaded in memory.

The solution, is to remove the hook to the event handler, the Form_Closing event is probably a good place to include this.

AddressControl.EventAddressChanged -= AddressControl_EventAddressChanged;

The better solution though is to avoid using static events.


Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

VSTS - Multiple tests with ID <guid> found

December 18, 2007 13:53 by admin

When you trying to run your tests and you come across this error message "Multiple tests with ID <guid> found", simply hit the Refresh button on the Test Manager window and you should be all set.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Debugging SQL Server 2005 Stored Procedures in Visual Studio

May 23, 2007 12:36 by admin

I used to use the debug feature in Query Analyzer when working with SQL Server 2000 quite a lot. There were a number of time when I did want to do this in SQL Server 2005 but couldn't quite figure it out. I looked high and low on SQL Server Management Studio to no avail.

The reason? Debugging was moved out of SQL Server Management Studio and into Visual Studio.

Debug SQL Server Stored Procedure

Read all about it in this article by Scott Mitchell.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5