Archive for the ‘ .Net ’ Category

NuGet packages folder

So yesterday I tweeted:

why doesn’t #NuGet allow me to specify where the ‘packages’ folder goes??

and @davidfowl from the team asked me a great question:

Why do you need that?

144 characters just ain’t enough so I figured a quick blog is the best way to answer.

I’ve been using NuGet for about 6 months or so and love the whole concept of picking what I want from a list and let it do the boring stuff (download, unzip, add references etc) is awesome, plus of course the uninstall works brilliantly.

One little thing concerned me but did not stop me from using it…after a while I noticed I had multiple ‘packages’ folders through my source.

Now what I have done for years with 3rd party libraries is put them into a ‘SharedComponents’ (or similarly named) directory which sits in my root Dev folder, easily accessible by all my projects. This means I have one place only where components are referenced. This means all of my projects have the same version, for me this is good (I know if you’re a big dev shop you may need different versions for different projects).

NuGet changed this, giving me a packages folder in ‘a few’ different places. This was not a problem until recently when I added Rx to a project using NuGet and then I started getting a weird ‘co-varient contravarient something’ error (I don’t remember the specifics of the error). The problem was that one of my shared projects was referencing a different (older) version of Rx (installed by NuGet) some time ago.

My fix was to go back to my ‘old school’ way of referencing the Rx .dlls, all projects pointing to the same dlls in the same folder. Worked immediately.

But that sucks. NuGet is a great concept and saves me plently of time, I should be able to and want to use NuGet but version issues is pretty much a show stopper for me, these problems usually surface as very obscure bugs that _can_ take alot of time to narrow down to the fact that there is a versioning problem.

So if I could specify where the ‘packages’ folder always ‘lives’ (ie override the default, which seems to be where the .sln file is?), then my versioning problem would no longer be a problem.

Another advantage is keeping source control of components to a minimum. With multiple ‘packages’ folders with multiple versions (often the same) of the same 3rd party components, all of these get stored in source control or the projects won’t build on a build box. Better to have one source….unless you have a compelling reason to keep multiple/different versions.

So for my usage it would be really helpful to be able to specify where the ‘packages’ folder lives 🙂 Anyone else agree/disagree…with reason?

Advertisements

ClickOnce – File Already Exists

The Problem

If your deploy a new version of your app and your users see “Cannot Start Application” when updating:

There could be many reasons, this quick post provides a few places to look to find what may be causing the File Already Exists problem.

Click on ‘Details’…and if your error looks something like this…then this most may help:

ERROR SUMMARY
	Below is a summary of the errors, details of these errors are listed later in the log.
	* Activation of ...\Start Menu\Programs\MyApp\MyApp\MyApp.appref-ms| resulted in exception. Following failure messages were detected:
		+ The file '...\Local Settings\Temp\Deployment\GOYP6PP3.TRR\61YND8Y2.Q2A\NaughtyFile.dll' already exists.

Where to look

Open up your ..\Application Files\MyApp1.0.0.0 directory (where 1.0.0.0 is the current build number)

Find and open the .manifest file, should be called MyApp.manifest.

Search for NaughtFile.dll (in the error above, NaughtyFile.dll was the name of the file that already exists), if your problem is the same as mine then you should find two references to this file in the manifest. In my case I had one reference which was a dependentAssembly and another which was a file.

Now, the project you are publishing may not have a direct reference to a dll and yet it still appears in the list of dependentAssemblies because a project it references does directly reference the dll. The easiest way to check this list is to go to the project properties, Publish Tab and open Application Files…

From there you see the list of files that are included, but I’ve noticed sometimes the list is not 100% truthful, if weird stuff is happening, open your project file in Notepad and closely examine the list of included and excluded files.

Note that you can only exclude a file in this list if the project has a direct reference to the file (this may not be true, but I just tried it and it didn’t exclude and I don’t have time for further investigation).

So our trouble, our extra ‘file’ reference came from an extension to msBuild that we have to explicitly include certain files (needed if you need the dll but cannot add a reference for example), that looks a little like this….

  <ItemGroup>
    <AdditionalPublishFile Include="..\..\NaughtyFileLocation\*">
      <Visible>False</Visible>
    </AdditionalPublishFile>
....

By changing the explicit inclusion to ‘not’ include that specific file (we needed other files in that directory), our problem went away. The key is ensuring that your manifest only has one entry for each file that is included…the trick is figuring out why there are multiple entries!

Good luck!

file:///C:/Dev/Release/Master/PmsMasterBuild_2.0.1.11.7zERROR SUMMARY
	Below is a summary of the errors, details of these errors are listed later in the log.
	* Activation of C:\Documents and Settings\mark.wallis\Start Menu\Programs\PMS Smart Client\PMS Smart Client\PMS Smart Client.appref-ms| resulted in exception. Following failure messages were detected:
		+ The file 'C:\Documents and Settings\mark.wallis\Local Settings\Temp\Deployment\GOYP6PP3.TRR\61YND8Y2.Q2A\EcsLite.Downloader.dll' already exists.

XAML Attribute Formatting

Is it just me or does the default setting for the XAML editor in Visual Studio make working with XAML more difficult?

If you want to make your life easier, change the Tools->Options setting to ‘Position each attribute on a separate line’.

What difference does it make? As you can see, below are two text boxes with all of the same properties set….

No wait, you can only see the properties of one, to see the properties of the other one you need to scroll horizontally, no problem I’ll just use my mouses horizontal scroll wheel….

No wait, it doesn’t have one of those, only a vertical scroller. Damn those mouse makers!

In C# it is possible to create a new object and set all of its properties all on one mega long horizontal line, but we don’t. Why? Because the code is more readable when you break it up vertically over a few lines. You can see all of the properties at once and you usually don’t need to scroll…and if you do you have a vertical scroll wheel on the mouse 🙂

Finding a Memory Leak in a .Net Application

Do You Have a Leak?

What do you do when you think your application has a memory leak?

I’m sure there are many options but this posting is about my experience with Red Gates ANTS memory profiler 5.1.

About Memory Management and the GC

There have been books written on this so I’m not going to attempt to explain. However I can’t stress enough how important it is to have at least a basic understanding about how the Garbage Collector works.

To compliment their products Red Gate have created a series of easy to understand on-line video’s about .Net Memory Management nicely broken down into several 5-10 minutes segments. These video’s are FREE so watch them!

If the video’s are not in depth enough for you, any article on the subject by Jeffrey Richter should satisfy your need for detailed explanations. Start with this one.

My Leak

Every time I opened and closed one of my controls, which was getting opened in a modal window, the memory used by the application increased and never went back down again. Which is weird because doesn’t .Net handle all memory management for me?

Do it does not.

So what is going on? The control in question has a dispose method, there’s nothing really tricky going on (no database connections etc) so how do I find out exactly what is causing the leak?

Finding the Leak

Enter ANTS memory profiler. I fire up the profiler, select my .exe and click ‘Start Profiling’.

Easy.

The app starts like normal but now the profiler has it under a microscope. Expect your app to run more slowly and make sure you have plenty of RAM.

I navigate to the screen where I can ‘launch’ the control that is leaking, then click ‘Take Memory Snapshot’.

Then I open and close the modal window say six times then click ‘Take Memory Snapshot’ once more.

Now we have two memory snapshots which we can compare. Stop Profiling for now, two is enough.

Click ‘Class List’, then in the grid click on the ‘Instance Diff (+/-)’ column header to sort by instance differences.

What we can clearly see now is a list of objects that are ‘alive’ in the program. What we care about is the difference in live instances from the first snapshot to the second. The ‘Instance Diff’ column provides this info. Now if we have a leak we should see an extra 6 live instances for our leaky control. So scroll down to the group of +6 items.

There are a couple of things of interest here in the profiler. First is yes we can see an extra six instance of our leaky control. Secondly, notice that ANTS puts your controls in bold. In this case we are looking for a specific problem but if you wanted to check for general memory leaks you can easily use the app for a while then scroll down until you see which of your objects is regularly increasing its instance count.

Ok great, we know it leaks, now what?

Dig a Little Deeper

Highlight the leaky object and click Instance List.

That will then show all 6 instance, just select one then click the ‘Object Retention Graph’ button.

In my case the graph appears empty, until I uncheck the ‘Hide’ box.

Now there’s some useful info…

In fact this tells me that there are several KeyEventHandlers that are stopping the GC from collecting my control.

Cool so back to the code and I add some code to unregister the handlers in the Dispose method.

_previousButton.Click -= PreviousButtonClick;
 _familyNameText.KeyDown -= Navigate;
 _givenNamesText.KeyDown -= Navigate;
...

Rebuild the solution and re-run the profiler. Take the initial snapshot, open close the leaky form half a dozen times, take the second snapshot.

Compare.

Now there are no more live instances of the leaky control! Our memory leak has been resolved.

Very easily!

Summary

It is almost certain that somewhere in your application there is a memory leak. With the right tool finding and resolving these leaks can be really easy, it just takes a little bit of time to familiarise yourself with the way the tool works.

The tools aren’t cheap but for any commercial application they are most definately worth the money. In this posting I used ANTS profiler from Red Gate, I am sure there are other tools out there that also do a great job, I just haven’t had the opportunity to use them. ANTS though is excellent (and no I do not have any association with them…beyond having bought a licence).

Events wired up to their handlers are often the ‘hidden’ cause of leaks. But even those of us who know how to manage memory in .Net often forget to do the right thing for whatever reason…usually time pressures. So I’d recommend explicitly building in some time into your project schedule to go hunting for memory leaks, find them before they go into production and everyone will sleep easier at night 🙂

ClickOnce Publish to Web with MSBuild

Summary

With ClickOnce you may publish to a web or file share location. This MSDN article tells you how to do it from Visual Studio, but doing it from VS is very limiting what you will end up wanting to do is publish using MsBuild from the command prompt.  This posting is not a comprehensive ‘how-to’ but has some useful tips, simple but painful lessons learnt through trial and error.

Project File Changes

Open up your Project.csproj in a text editor (I always use notepad++). Set these properties, add them if they are not there already….they should be near the top of the file and probably not together.

 <IsWebBootstrapper>true</IsWebBootstrapper>
 <InstallFrom>Web</InstallFrom>
 <PublishDir>C:\Dev\Release\$(BuildEnvironment)\</PublishDir>

InstallFrom

As far as I can tell this can either be Web or Unc

IsWebBootstrapper

This one is really important, if you do not set this to true the publish will work fine but you will have problems installing. If you see an error that looks something like this

SOURCES
 Deployment url            : file:///C:/Documents%20and%20Settings/Administrator.HP275/Local%20Settings/Temporary%20Internet%20Files/Content.IE5/QTJPP0ZG/MyApp.Shell.application

ERROR SUMMARY
 Below is a summary of the errors, details of these errors are listed later in the log.
 * Activation of C:\Documents and Settings\Administrator.HP275\Local Settings\Temporary Internet Files\Content.IE5\QTJPP0ZG\MyApp.Shell.application resulted in exception. Following failure messages were detected:
 + Downloading file:///C:/Documents and Settings/Administrator.HP275/Local Settings/Temporary Internet Files/Content.IE5/QTJPP0ZG/MyApp.Shell.application did not succeed.

the likely cause of the problem is the IsWebBootstrapper value is false. Note that VS kindly changes this value for you sometimes…so be careful! The clue that this is the cause is of course the fact that the installer is trying to find the file from a local path.

PublishDir

This is still a unc path, preferably to the dir of the virtual directory in IIS. However if the machine you are publishing from does not have write access to that location on the network, you can publish to a local location then copy the files to the secure machine.

Batch File

I like to create a separate batch file for each environment that I need to publish to, e.g. QA, Training, Production etc.

The reason is, SOME of the MsBuild variables that need to be set must be passed in (as far as I can tell) from the command prompt to MsBuild.

So this is what my batch files look like (check out my posting on MsBuild and multiple environments for details on the extra properties).

msbuild /t:Publish /p:Configuration=Release /p:BuildEnvironment=QA /p:ApplicationVersion=1.0.3.67 /p:UpdateUrl=http://MachineNameOrIP/Release/QA/ /p:InstallUrl=http://MachineNameOrIP/Release/QA/

InstallUrl and UpdateUrl are both properties which apparently need to be passed in as parameters which is why I put them in the batch file.

The ApplicationVersion I still do manually because I haven’t tried setting up the automated solution yet.

IIS

To publish from a web address you will need to setup a virtual directory in IIS.

The main ‘Gotcha’ I encountered was setting the execute permissions to Scripts and executables. It must be Scripts only! This post help me figure out what the hell was going wrong when I had the wrong setting.

Final Note

If you are publish to the web then you most likely want/need a publish page, check out my other posting on creating the publish.html file as part of your build (this file gets created when you publish from VS but you stop getting it as soon as you publish directly from MsBuild)

Happy publishing 🙂

MSBuild Customizable Targets

MSBuild has a number of targets that have been specifically created to be ‘overwritten’ or customized.

I have never seen a compiled list of these targets so here is a list of all the ones that I am aware of….

BeforeBuild
AfterBuild
BeforeRebuild
AfterRebuild
BeforeResolveReferences
AfterResolveReferences
BeforeResGen
AfterResGen
BeforeCompile
AfterCompile
BeforeClean
AfterClean
BeforePublish
AfterPublish

These targets are all safe to customize because in Microsoft.Common.targets they do not have any ‘implementation’, i.e. they get run but do absolutely nothing. You could (I believe) override any target you want to but if you do be aware that your ‘override’ entirely replaces what is in MSBuild. So if you absolutely must override a target that has an implementation, unless you completely understand 100% what you are doing, I recommend copying the full implementation and working your customization into the existing logic.

I would also strongly suggest that you NEVER modify Microsoft.Common.targets directly, that is just asking for pain.

ClickOnce – Creating Publish Page from msbuild

ClickOnce via msbuild

The Problem

When you publish from Visual Studio, the publish directory gets three files:-

  • Publish.htm
  • setup.exe
  • MyApp.application

but when you publish using msbuild you do not get the Publish.htm.

This post covers one approach to ensure you also get a nice publish.htm file. Actually it’s a two part blog, in the second part I’ll cover how to simplify your deployment process for multiple environments.

As a pre-requisite you’ll need to install msbuild community tasks.

All credit for this post belongs to my good friend Craig Hunter, this is pretty much a slightly modified version of his solution.

Step One – Create Customization File

This step in kind of optional. All subsequent steps may be done within your .csproj, it is just my preference to put all of my customizations into a separate file.

1. In your project file directory, create a new file called Customized.targets (actually call it whatever you want).
2. Now open your .csproj in notepad++, copy the first and last lines and add them to Customized.targets. Should look something like this

<Project DefaultTargets=”Build” xmlns=”http://schemas.microsoft.com/developer/msbuild/2003&#8243; ToolsVersion=”3.5″>
</Project>

3. At the bottom of your .csproj add these two lines

<Import Project=”Customized.targets” />
<Import Project=”$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets” />

What is not optional is adding the Import of the MSBuild community tasks.

Step Two – Add Publish Template

  1. In your project file directory, add a new directory called Publish.
  2. Add this file to that directory.

You don’t really need to but I also added the directory to my project. At the very least you do have to add it to source control (otherwise it won’t get to the build machine)

Step Three – Customizations

Add these customizations to your Customized.targets file. Remove the numbers, they are just there for reference below…

1.	<PropertyGroup>
		<BuildEnvironment>DEV</BuildEnvironment>
	</PropertyGroup>

2.	<Choose>
		<When Condition=" '$(BuildEnvironment)' == 'DEV' ">
		  <PropertyGroup>
		    <PublishDir>\\MachineIP\ReleaseDirectory\$(BuildEnvironment)\</PublishDir>
		  </PropertyGroup>
		</When>
		<When Condition=" '$(BuildEnvironment)' == 'QA' ">
		  <PropertyGroup>
		    <PublishDir>\\MachineIP\ReleaseDirectory\$(BuildEnvironment)\</PublishDir>
		  </PropertyGroup>
		</When>	</Choose>

3.	<PropertyGroup>
		<!-- Note this must be done AFTER the above Choose (so PublishDir is set)-->
		<PublishFilePath>$(PublishDir)publish.html</PublishFilePath>
	</PropertyGroup>

4.	<ItemGroup>
		<Tokens Include="PublisherName">
		  <ReplacementValue>$(PublisherName)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="ProductName">
		  <ReplacementValue>$(ProductName)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="ApplicationVersion">
		  <ReplacementValue>$(ApplicationVersion)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="Prerequsites">
		  <ReplacementValue>@(BootstrapperPackage->'&lt;li&gt;%(ProductName)&lt;/li&gt;','%0D%0A')</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="Username">
		  <ReplacementValue>$(Username)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
	</ItemGroup> 

5.	<Target Name="AfterPublish">
		<Time Format="dd/MM/yyyy HH:mm">
		  <Output TaskParameter="FormattedTime" PropertyName="PublishTime" />
		</Time>
		<!-- Finalise the publish.htm template file and copy it to the publish location -->
		<TemplateFile Template="Publish\publish.template.html" Tokens="@(Tokens)" OutputFilename="$(PublishFilePath)" />
		<FileUpdate Files="$(PublishFilePath)" Regex="\${PublishTime}" ReplacementText="$(PublishTime)" />
	</Target>

1. More on the BuildEnvironment property in a later posting. It’s not essential just remove all references to it if you want to remove it.

2. Also more on this in a later post, it is for specifying details for multiple environments. In the provided sample the PublishDir is the same machine and parent directory for both DEV and QA with a separating sub directory of the environment name. Don’t forget to SHARE the ReleaseDirectory folder!

3. Tells MSBuild where to put the publish.html file (name it what you want)

4. The publish.template.html has a number of tokens which need to be set.  Adjust these how you want, add or remove whatever tokens you want in the template.

5. After MSBuild finishes publishing it will run this section which creates the publish.html file using the token values.

Save those changes and you are done, you should now be able to run MSBuild, call publish and have a publish.html created for you with relevant information.

Step Four – Run MSBuild

Open Visual Studio command prompt, navigate to your project directory, execute (this assumes you only have one project file in the directory):

msbuild /t:Publish /p:Configuration=Release /p:BuildEnvironment=DEV

Done!

Why Bother?

If you get the file from VS why then care about what happens when publishing directly from msbuild?

I can think of three reasons why you need to publish from msbuild.

First, ideally developers should never publish from their machines.  (I say ideally because I have to raise a guilty hand and confess this is currently what I am doing…sometimes cirumstance forces bad practice upon us). This means ideally you have a build machine and it is from this machine only that releases should be done. So if you want to use VS to do the publish then you need to install and licence that machine.

Secondly, you want to be able to do a release from the command line, you don’t want to muck around starting VS, wait for the solution to load, open properties and click publish, what a waste of time, with msbuild you can create a batch file or two and start the publish process in the time it takes you to navigate to that directory.

Finally, the customization options available to you from within VS is too limiting. For example, if you are using VS to publish to multiple environments, how do you handle changing the parameters for each environment?

Some Notes

You can of course still run publish from VS but I don’t recommend it, get out of that bad habit and start using MSBuild directly. However if you insist on using VS, if you make any changes to Customization.targets, you need to unload and reload your project in VS for those changes to be ‘picked up’ by VS.

Please let me know if you identify any flaws or improvements that may be made with this approach.

<Choose>
<When Condition=” ‘$(BuildEnvironment)’ == ‘DEV’ “>
<PropertyGroup>
<BaseUrlPmsServices>https://ecsport3.cps.com.au/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecsport3.cps.com.au/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edasport.cps.com.au:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecstest.cps.com.au/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\172.16.101.101\ReleaseMark\$(BuildEnvironment)\</PublishDir><!– InstallUrl>It seems that installUrl doesn’t get picked up if set here, must be fed in with the msbuild command arguments.</InstallUrl –>
<!– ApplicationVersion is set in the publishENV.bat –>
</PropertyGroup>
</When>
<When Condition=” ‘$(BuildEnvironment)’ == ‘SUB’ “>
<PropertyGroup>
<BaseUrlPmsServices>https://ecspmsport1/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecspmsport1/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edas2-port1:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecspmshq/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\ecspmsport1\SmartClient\</PublishDir>
</PropertyGroup>
</When>
<When Condition=” ‘$(BuildEnvironment)’ == ‘DPS’ “>
<PropertyGroup>
<BaseUrlPmsServices>https://ecspmsport2/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecspmsport2/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edas2-port2:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecspmshq/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\ecspmsport2\SmartClient\</PublishDir>
</PropertyGroup>
</When>
</Choose>