ClickOnce – Exception reading manifest from file

the manifest may not be valid or the file could not be opened

This is a problem that you can run into when you publish an application using ClickOnce.

The error message provided by ClickOnce is a little obscure and there may well be a number of different causes, this posting is about what was causing the problem in my case.

This is a more complete look at the error

What Causes the Problem?

Multiple references to the same dll(s) (not necessarily just a project reference).

In our case we were pulling in non .net dll’s from two different directories that each contained about 5 dll’s that existed in both directories. Same version and everything, versioning was not causing the problem.

As soon as we removed the duplicates the problem went away.

We also experienced the same problem when we were pulling a configuration file explicitly from one location but had also added the file to the main project.¬† So once again because a file with the same name was ‘included’ in the publish, ClickOnce throws an error because the manifest is invalid.

This guy found the problem was due to an Enterprise Library dll. I don’t know the details but I’d be willing to bet that he had a reference to two different versions of the same dll in two different projects.

Summary

While it would be nice to get a clearer error message I think what ClickOnce is doing here is pretty nice. It is making sure that you don’t get into any trouble with different references to the same file…which could be a different version and give you a world of subtle, very difficult to find bugs.

I hope this makes sense…it has been written very quickly ūüôā

ClickOnce Deployment Error

Full Error

See this posting for description of thi error and what the problem was….

PLATFORM VERSION INFO
Windows             : 5.1.2600.196608 (Win32NT)
Common Language Runtime     : 2.0.50727.3603
System.Deployment.dll         : 2.0.50727.3053 (netfxsp.050727-3000)
mscorwks.dll             : 2.0.50727.3603 (GDR.050727-3600)
dfdll.dll             : 2.0.50727.3053 (netfxsp.050727-3000)
dfshim.dll             : 2.0.50727.3053 (netfxsp.050727-3000)

SOURCES
Deployment url            : file:///C:/Dev/Release/DEV/MyApp.application

IDENTITIES
Deployment Identity        : MyApp.Shell.application, Version=1.2.3.5, Culture=neutral, PublicKeyToken=12ebb91613a16909, processorArchitecture=msil

APPLICATION SUMMARY
* Installable application.

ERROR SUMMARY
Below is a summary of the errors, details of these errors are listed later in the log.
* Activation of C:\Dev\Release\DEV\MyApp.Shell.application resulted in exception. Following failure messages were detected:
+ Exception reading manifest from file:///C:/Dev/Release/DEV/Application%20Files/MyApp.Shell_1_2_3_5/MyApp.Shell.exe.manifest: the manifest may not be valid or the file could not be opened.
+ Parsing and DOM creation of the manifest resulted in error. Following parsing errors were noticed:
-HRESULT:     0x80070c89
Start line:     0
Start column:     0
Host file:
+ Master  did not send an update notice for directory  at the expected time. (Exception from HRESULT: 0x80070C89)

COMPONENT STORE TRANSACTION FAILURE SUMMARY
No transaction error was detected.

WARNINGS
There were no warnings during this operation.

OPERATION PROGRESS STATUS
* [29/12/2009 2:02:27 PM] : Activation of C:\Dev\Release\DEV\MyApp.Shell.application has started.
* [29/12/2009 2:02:30 PM] : Processing of deployment manifest has successfully completed.
* [29/12/2009 2:02:30 PM] : Installation of the application has started.

ERROR DETAILS
Following errors were detected during this operation.
* [29/12/2009 2:02:30 PM] System.Deployment.Application.InvalidDeploymentException (ManifestParse)
– Exception reading manifest from file:///C:/Dev/Release/DEV/Application%20Files/MyApp.Shell_1_2_3_5/MyApp.Shell.exe.manifest: the manifest may not be valid or the file could not be opened.
– Source: System.Deployment
– Stack trace:
at System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri)
at System.Deployment.Application.DownloadManager.DownloadManifest(Uri& sourceUri, String targetPath, IDownloadNotification notification, DownloadOptions options, ManifestType manifestType, ServerInformation& serverInformation)
at System.Deployment.Application.DownloadManager.DownloadApplicationManifest(AssemblyManifest deploymentManifest, String targetDir, Uri deploymentUri, IDownloadNotification notification, DownloadOptions options, Uri& appSourceUri, String& appManifestPath)
at System.Deployment.Application.ApplicationActivator.DownloadApplication(SubscriptionState subState, ActivationDescription actDesc, Int64 transactionId, TempDirectory& downloadTemp)
at System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
— Inner Exception —
System.Deployment.Application.InvalidDeploymentException (ManifestParse)
– Parsing and DOM creation of the manifest resulted in error. Following parsing errors were noticed:
-HRESULT:     0x80070c89
Start line:     0
Start column:     0
Host file:
– Source: System.Deployment
– Stack trace:
at System.Deployment.Application.Manifest.AssemblyManifest.LoadCMSFromStream(Stream stream)
at System.Deployment.Application.Manifest.AssemblyManifest..ctor(FileStream fileStream)
at System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri)
— Inner Exception —
System.Runtime.InteropServices.COMException
РMaster  did not send an update notice for directory  at the expected time. (Exception from HRESULT: 0x80070C89)
– Source: System.Deployment
– Stack trace:
at System.Deployment.Internal.Isolation.IsolationInterop.CreateCMSFromXml(Byte[] buffer, UInt32 bufferSize, IManifestParseErrorCallback Callback, Guid& riid)
at System.Deployment.Application.Manifest.AssemblyManifest.LoadCMSFromStream(Stream stream)

COMPONENT STORE TRANSACTION DETAILS
No transaction information is available.

MSBuild and Multiple Environments

Even if you are the kind of developer who rides into work on the back of a raging bull wearing one of your many cowboy hats whistling your favourite Willie Nelson tune, it is very likely you have multiple environments for your software. At the very least you have your Developer and Production environments, hopefully you also have QA and perhaps BUILD and UAT.

Each of these environments requires subtle changes (usually to a config file) that must be made when you create a release/build,  e.g.  database connection string.

So this post is about one technique you can use with MSBuild to simplify the process of creating a release for these different environments. Using this technique also makes creating releases much faster and less error prone. It has a ClickOnce flavour but the core concepts are relevant for any method you use to promote new versions of your software.

Once you’ve read this posting, checkout this one for an extension of the ideas presented here and a subtly different way of creating your releases using a ‘Master Build’ approach.

Scenario’s

Creating a release is just one phase of the development lifecycle. We need to ensure that any approach we take to simplify the release process does not interfere with other phases. These are the scenario’s that our approach must work seamlessly and autonomously for:-

  1. Developer, get the latest version, build and debug the app.
  2. Build machine detects a change, get latest version, build, run tests, create successful build.
  3. Publish (via ClickOnce) a successful build to each environment using a batch file (or other similar, not interactive process).
  4. Developer needs to debug a non DEV environment.
  5. Run tests on Developer machine and Build box.

Let’s assume for this posting that we have these environments: DEV, BUILD, QA, PROD

Setting Up Your Customizations

Look at my other posting and do the pre-requisite (install MSBuild Community Tasks) and Step One.

Now in your new Customized.targets file add this to the top (if you haven’t already)

<PropertyGroup>
  <BuildEnvironment>DEV</BuildEnvironment>
</PropertyGroup>

Then directly underneath add:

<Choose>
 <When Condition=" '$(BuildEnvironment)' == 'DEV' ">
     <PropertyGroup>
        <BaseUrlWebServices>https://mywebserviceaddress</BaseUrlWebServices>
        <PublishDir>\\MyMachine\ReleaseFolder\$(BuildEnvironment)\</PublishDir>
     </PropertyGroup>
 </When>
 <When Condition=" '$(BuildEnvironment)' == 'QA' ">
     <PropertyGroup>
       <BaseUrlWebServices>https://mywebserviceaddress</BaseUrlWebServices>
       <PublishDir>\\MyMachine\ReleaseFolder\$(BuildEnvironment)\</PublishDir>
     </PropertyGroup>
 </When>
</Choose>

(for brevity I have only put DEV and QA. BUILD and PROD should be there to).

You are now set up and ready to go with customizations for different environments ‘within’ MSBuild. So lets discuss what we have done here and how we’re going to use it.

New Property – BuildEnvironment

This is a brand new property that MS Build knows nothing about. It is important to set the default here to DEV to deal with scenario 1 mentioned above…developer getting the latest version and debugging the app. For each of the other scenarios we can pass in the environment as a parameter to MSBuild, but more on that later.

Very simply we use the value of this parameter to set the value of a number of other variables.

Choose

In this section (from the xml above) we list all possible values for BuildEnvironment and set other variables that are environment specific. Easy ūüôā

As an example I’ve included one other new property, BaseUrlWebServices. I’m going to use this property to update my app.config later. Note that these properties can be brand new ones or can be ones that MSBuild knows about and uses, just double check any values that MSBuild knows about because I have noticed that some are successfully set using this approach but some failed to be set. E.g the PublishUrl property works but InstallUrl does not (didn’t investigate why). (side note -The value InstallUrl may be changed by passing it in as a paramater to MSBuild).

The other example property is a built in MSBuild property, the PublishDir used by ClickOnce to determine where to publish a release. In the example above it has the same value for both environments, but uses the BuildEnvironment variable as the destination sub directory.

Using The Values

Ok so now we have these different values set up for all of our environments, how do we use them?

PublishDir is sorted already,  MSBuild will automatically pick it up when publishing.

BaseUrlWebServices we want to use to update values in our app.config file.

Update App.Config with Environment Specific Data

First we need to change our app.config file so that is has a value we can consistently update.

So where you have something like this:-

<endpoint address="https://server.com/services/UserService.svc"

Replace it with this:-

<endpoint address="SomeUniqueKeyWithAGoodName/UserService.svc"

Now the tricky bit. At what ‘stage’ in the build/publish process do we update the app.config file? Ideally we don’t want to update the app.config file at all, what we want to update is the config file that gets created in the bin directory, Myapp.exe.config. Why? Well if you update the app.config file then the update will only succeed once…the keys will all be updated with their respective replacement values. While this is kind of OK the main problem is this scenario; developer gets latest version, runs the app (which updates the config file) then modifies the config file (adds a new key value pair) then checks in the change which now not only includes their new key value pair but also the environment keys are now values.

For ClickOnce, we also want to ensure that the changes are applied BEFORE the manifests are created, otherwise the application will not install (because a file has been modified).

So given this list of possible targets to override in MSBuild, which should we use? I use two, this is my approach and why….

1. Override BeforeBuild and AfterBuild

<Target Name="BeforeBuild"
    DependsOnTargets="ReleaseModeUpdateConfig" />
<Target Name="AfterBuild"
    Condition=" '$(Configuration)' == 'Debug' "
    DependsOnTargets="UpdateConfigFileForEnvironment" />

I have removed a couple of extra ‘DependsOnTargets’ items which are specific to my project. It is important to note that everything I do in AfterBuild I only want to happen when in Debug mode but for BeforeBuild I have some targets I want to run only in ReleaseMode and some also in Debug mode.

2. Create ReleaseModeUpdateConfig

<Target Name="ReleaseModeUpdateConfig"
    Condition=" '$(Configuration)' == 'Release' "  
    DependsOnTargets="UpdateConfigFileForEnvironment" />

The only reason this has its own target is so that I can apply the Condition to ensure it only gets run in Release mode.¬† I only want it to run in Release mode because when I Publish it is always in Release mode and in day to day development most developers will work in Debug mode, so the update of the config file won’t interfere with their work.

I would prefer to use this property GenerateClickOnceManifests, it gets set to true when you call the Publish target…but for some reason it is always true, even when only running the Build target.

3. Create the UpdateConfigFileForEnvironment target

<Target Name="UpdateConfigFileForEnvironment">

 <PropertyGroup>
   <AppConfigFileName>$(TargetPath).config</AppConfigFileName>
   <AppConfigFileName Condition=" '$(Configuration)' == 'Release' ">app.config</AppConfigFileName>
 </PropertyGroup>

 <!-- Update Service address  -->
 <FileUpdate
   Files="$(AppConfigFileName)"
   Encoding="ASCII"
   Regex="SomeUniqueKeyWithAGoodName"
   ReplacementText="$(BaseUrlWebServices)" />
</Target>

I create a new property here, AppConfigFileName which controls which file actually gets updated. The build mode drives this so if we are in Release mode then we update the app.config directly but if we are in any other mode then we update the config file that gets created in the bin directory….myApp.exe.config.

The FileUpdate section requires msbuild community tasks and simply replaces the keys (in this case, SomeUniqueKeyWithAGoodName), with the environment specific value.

Before and After

When publishing it is very important that the app.config update occurs in the BeforeBuild override because the creation of the manifests occurs during CoreBuild, so AfterBuild is too late. Note also that MSBuild will always use the app.config file that is in your .csproj directory when creating the manifests.

AfterBuild is used when we’re updating myApp.exe.config because if you start with a clean bin directory the file won’t exist in BeforeBuild.

ClickOnce Deployment With Our Changes

Ok so we have these environment specific information setup, now what do we do, how do we use it to create a new release?

Easy!

Create a batch file (in your csproj directory), called publishQA.bat, in it put this:-

@ECHO OFF

msbuild /t:Publish /p:Configuration=Release /p:BuildEnvironment=QA /p:ApplicationVersion=1.2.3.5

(of course you need to change your version number).¬† What we’re doing here is simply telling msbuild to run the ‘Publish’ target, ensuring that it builds in Release mode and we pass in our verion number. Importantly we also tell it which environment we are publishing for so MSBuild will pick up our environment specific information.

Create a similar file for each environment then when you want to publish to QA all you need to do is open up a Visual Studio command prompt (in the directory with the batch files), then type publishQA -> Enter….a new release will be created for the QA environment…with all of the correct environment specific information!

Build Box Scenario

Making this work with the Build box scenario should be relatively simple. All we need to do is ensure the BuildEnvironment property gets set. A couple of possible solutions are:-

  • Make the BuildEnvironment value come from an Environment Variable on the machine
  • Or set the BuildEnvironment after the build process ‘gets’ the latest version when a change is detected

Run Tests Scenario

The problems you will face in this scenario will vary greatly depending on how you have things set up. I can only describe what I do, the challenges faced with my setup and how to make it work.

My setup:-

  1. A separate test project for each assembly
  2. Each project which requires an app.config has one but I never modify these files directly
  3. I only have one ‘master’ config file (which lives in the main projects directory, i.e. the one that is usually set as the startup project)
  4. All projects that need a config file, e.g. Test projects, have a pre-build event which copies (XCOPY) the config file from the ‘master’ config file location

For me the key advantages of this setup is simplicity and maintainability. I know I only have one config file that I need to modify for everything.

Ok so before going on, let me clarify something. Most Test projects won’t care about the config file because they should be testing the logic and using mock objects etc. However I like to have some ‘Integration‘ unit test projects that do care about the contents of the config file and which server they are talking to etc.

The PROBLEM with this setup is with the environmental specific info. With the current setup the raw config file isn’t valid for use until my ‘main’ project is built so my test projects have a problem. Or do they? We definately do not want to duplicate the data and logic that is in the Customized.targets file so how do we ensure our config file is getting the correct values for these integration test projects?

Easy!

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

Just import Customized.targets into the integration test projects as well! (Note that you must also import the MSBuild Community tasks targets). This means that when a developer runs the tests on his or her machine in Debug mode they will run successfully and also when the Build Box builds and runs the tests in Release mode it will also work…and be run against the correct environment.

This is the pre-build event that pulls the config file from the ‘main’ project to the test project…

XCOPY ..\..\..\..\MyApp\app.config $(ProjectDir) /R /Y

Summary

There are many ways you could potentially solve the problem of environment specific information. I like this approach for these reasons:-

  • All the environment specific information is in one file
  • Unless they work in Release mode, the approach does not interfere with Developers getting on with their work
  • Creating new releases to any environment is quick, easy and reliable.

I’m always looking for ways of improving processes so please do point out any flaws you find or means of improving this approach. If you are using a completely different approach I’d be very interested in hearing about it and what you see as the pro’s and con’s of that approach vs this one.

Happy building! ūüôā

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>

TFS Unlock Exclusive Checkout

I’ve been using TFS for the project I have been working on these past few months. I have to say that after using SVN that I’m not loving TFS, although to be fair we’re mainly using TFS much like source safe, i.e. as a repository without making much use of the work items etc.

The main thing I don’t like about it is it gets in your way. When working with SVN as the repo you work completely disconnected, make your changes then submit them when you are ready…it’s only then that you have to interact with SVN. TFS on the other hand still has this old school idea of checking items out which means every time you change a file you have to interact with TFS, usually not a problem but gets annoying when the repo regularly takes 5-10 seconds to peform the checkout.

The Problem

So today I discovered a feature in TFS that I like – removing a lock on an exclusively checked out file.

You know the issue, you want to work on a file but your colleague has the file checked out exclusively and you get the error, blah.cs – File is exclusively checked out by another user.

Then he can’t check it in because then he’d have to check in everything else and it’s not working right now…and he can’t undo the checkout because there are many changes…blah blah blah.

The Solution

Well I assumed that TFS would be like SourceSafe and these were really the only options but NO! TFS provides a neat little third option…unlock!

unlockTFS

The guy who has the file exclusively checked out has to do the unlocking of course but all he has to do is right click on the file in solution explorer, click unlock and voila….you can now also check out the file. Too easy!

Of course you have to have multiple checkouts turned on on the TFS server, seriously though, if you do not have multiple checkouts turned on…..WHY???

Ode to Michael Jackson

Composed almost entirely of song titles….can you count how many?

2 Bad Michael you are Gone Too Soon…seems Heaven Can(t) Wait, Whatever Happens despite your Bad Monkey Business you were always Invincible.

I’ll always Remember The Time I saw the Man In The Mirror, the Smooth Criminal Burn This Disco Out on the HIStory tour. Speechless I had a huge Smile and Butterflies in my stomach…You Rock My World.

Tell me MJ, Is It Scary, is it Dangerous, are there Ghosts…are there Just Good Friends or is there Someone In the Dark? I’m sure You Are Not Alone.

Whatever Happens don’t Cry…Jam at 2000 Watts until the Break Of Dawn and there’s Blood On The Dance Floor…you were a Thriller!